//Copyright 2010 Balazs Keri, Imre Keri
//
//This file is part of FireworksCreator.
//
//FireworksCreator is free software: you can redistribute it and/or modify
//it under the terms of the GNU General Public License as published by
//the Free Software Foundation, either version 3 of the License, or
//(at your option) any later version.
//
//FireworksCreator is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with FireworksCreator.  If not, see <http://www.gnu.org/licenses/>.
//
#include <global.h>
#include <algorithm>
#include <QApplication>
#include <model/emittertemplate.h>
#include <model/group.h>
#include <model/particletemplate.h>
#include <model/root.h>
#include "document.h"
#include "modeldataobjectadapter.h"
#include "primitives.h"
using namespace Primitives;
using namespace model;
//
UiError RemoveObjectFromContainment::initialize(Id p_id,Document *p_doc)
{
   Identified *const object=p_doc->lookup_object(p_id);
   Root *const r=p_doc->get_root();
   if(object==r->root_group)
      return UiError(qApp->translate("Primitive","The root group can not be removed."));
   if(r->child.contains(object))
      return UiError(qApp->translate("Primitive","Try to remove an object while it has children."));
   if(r->child.contains(object))
   {
      // this code works but may leave objects with 0 parents so do not support this case
      Root::IdentifiedList const children=r->child.value(object);
      for(Root::IdentifiedList::const_iterator child=children.begin();child!=children.end();++child)
      {
         saved_children.append(SavedParentPair((*child)->get_id(),r->parent.value(*child).indexOf(object)));
      }
   }
   Root::IdentifiedList const parents=r->parent.value(object);
   for(Root::IdentifiedList::const_iterator parent=parents.begin();parent!=parents.end();++parent)
   {
      saved_parents.append(SavedParentPair((*parent)->get_id(),r->child.value(*parent).indexOf(object)));
   }
   return UiError();
}
UiError RemoveObjectFromContainment::exec_impl(Id p_id,Document *p_doc)
{
   Identified *const object=p_doc->lookup_object(p_id);
   Root *const r=p_doc->get_root();
   for(SavedParentType::iterator child=saved_children.begin();child!=saved_children.end();++child)
   {
      r->parent[p_doc->lookup_object(child->first)].removeAt(child->second);
   }
   r->child.remove(object);
   for(SavedParentType::iterator parent=saved_parents.begin();parent!=saved_parents.end();++parent)
   {
      r->child[p_doc->lookup_object(parent->first)].removeAt(parent->second);
   }
   r->parent.remove(object);
   return UiError();
}
UiError RemoveObjectFromContainment::undo_impl(Id p_id,Document *p_doc)
{
   Identified *const object=p_doc->lookup_object(p_id);
   Root *const r=p_doc->get_root();
   for(SavedParentType::iterator child=saved_children.begin();child!=saved_children.end();++child)
   {
      Identified *const ch=p_doc->lookup_object(child->first);
      r->parent[ch].insert(child->second,object);
      r->child[object].append(ch);
   }
   for(SavedParentType::iterator parent=saved_parents.begin();parent!=saved_parents.end();++parent)
   {
      Identified *const pa=p_doc->lookup_object(parent->first);
      r->child[pa].insert(parent->second,object);
      r->parent[object].append(pa);
   }
   return UiError();
}
void RemoveObjectFromContainment::store_data_impl(QDataStream& p_stream) const
{
   p_stream<<saved_children<<saved_parents;
}
void RemoveObjectFromContainment::restore_data_impl(RestoreStream& p_stream)
{
   p_stream>>saved_children>>saved_parents;
}
//
//
//
Reset::Reset()
:
   Primitive(type_Reset)
{;}
void Reset::exec_reset(Document *p_doc)
{
   Reset reset;
   reset.exec(p_doc);
}
//
InsertContainment::InsertContainment()
:
   Primitive(type_InsertContainment)
{
}
InsertContainment::InsertContainment(const Document *p_doc,Identified *p_parent,int p_parent_position,Identified *p_child,int p_child_position)
:
   Primitive(type_InsertContainment),
   parent_id(p_parent->get_id()),child_id(p_child->get_id()),
   parent_position(p_parent_position),child_position(p_child_position)
{
   const Root *const r=p_doc->get_root();
   if(p_child==r->root_group)
      throw UiError(qApp->translate("Primitive","Try to insert the root group as child."));
   if(p_parent==p_child)
      throw UiError(qApp->translate("Primitive","Try to insert object as child of itself."));
   const Root::IdentifiedList &parents=r->parent[p_child];
   Root::IdentifiedList const children=r->child.value(p_parent);
   if(parents.contains(p_parent))
      throw UiError(qApp->translate("Primitive","Try to insert duplicate child object."));
   if(r->test_containment(p_child,p_parent))
      throw UiError(qApp->translate("Primitive","Try to create circular parent-child relationship."));
   if(parent_position<0||parent_position>parents.length())
      parent_position=parents.length();
   if(child_position<0||child_position>children.length())
      child_position=children.length();
   prepare_base(p_doc);
}
InsertContainment::~InsertContainment( )
{
}
Primitive *InsertContainment::create(unsigned int p_type,RestoreStream &p_stream)
{
   return new InsertContainment;
}
UiError InsertContainment::exec_impl(Document *p_doc)
{
   Identified *const parent=p_doc->lookup_object(parent_id);
   Identified *const child=p_doc->lookup_object(child_id);
   Root::IdentifiedList &parents=p_doc->get_root()->parent[child];
   parents.insert(parent_position,parent);
   Root::IdentifiedList &children=p_doc->get_root()->child[parent];
   children.insert(child_position,child);
   return UiError();
}
UiError InsertContainment::undo_impl(Document *p_doc)
{
   Identified *const parent=p_doc->lookup_object(parent_id);
   Identified *const child=p_doc->lookup_object(child_id);
   p_doc->get_root()->child[parent].removeAt(child_position);
   p_doc->get_root()->parent[child].removeAt(parent_position);
   if(p_doc->get_root()->child[parent].empty())
   {
      p_doc->get_root()->child.remove(parent);
   }
   return UiError();
}
void InsertContainment::store_data_impl(QDataStream &p_stream) const
{
   p_stream<<parent_id<<child_id<<parent_position<<child_position;
}
void InsertContainment::restore_data_impl(RestoreStream &p_stream)
{
   p_stream>>parent_id>>child_id>>parent_position>>child_position;
}
//
RemoveContainment::RemoveContainment()
:
   Primitive(type_RemoveContainment)
{
}
RemoveContainment::RemoveContainment(const Document *p_doc,Identified *p_parent,Identified *p_child)
:
   Primitive(type_RemoveContainment),
   parent_id(p_parent->get_id()),child_id(p_parent->get_id())
{
   const Root *const r=p_doc->get_root();
   if(p_child==r->root_group)
      throw UiError(qApp->translate("Primitive","Try to remove non-existing containment."));
   const Root::IdentifiedList &parents=p_doc->get_root()->parent[p_child];
   parent_position=parents.indexOf(p_parent);
   if(parent_position==-1)
      throw UiError(qApp->translate("Primitive","Try to remove non-existing containment."));
   if(parents.length()==1)
      throw UiError(qApp->translate("Primitive","Try to remove child from its single parent."));
   child_position=p_doc->get_root()->child[p_parent].indexOf(p_child);
   Q_ASSERT(child_position!=-1);
   prepare_base(p_doc);
}
RemoveContainment::~RemoveContainment()
{
}
Primitive *RemoveContainment::create(unsigned int p_type,RestoreStream &p_stream)
{
   return new RemoveContainment;
}
UiError RemoveContainment::exec_impl(Document *p_doc)
{
   Identified *const parent=p_doc->lookup_object(parent_id);
   Identified *const child=p_doc->lookup_object(child_id);
   p_doc->get_root()->child[parent].removeAt(child_position);
   p_doc->get_root()->parent[child].removeAt(parent_position);
   if(p_doc->get_root()->child[parent].empty())
   {
      p_doc->get_root()->child.remove(parent);
   }
   return UiError();
}
UiError RemoveContainment::undo_impl(Document *p_doc)
{
   Identified *const parent=p_doc->lookup_object(parent_id);
   Identified *const child=p_doc->lookup_object(child_id);
   Root::IdentifiedList &parents=p_doc->get_root()->parent[child];
   parents.insert(parent_position,parent);
   Root::IdentifiedList &children=p_doc->get_root()->child[parent];
   children.insert(child_position,child);
   return UiError();
}
void RemoveContainment::store_data_impl(QDataStream& p_stream) const
{
   p_stream<<parent_id<<child_id<<parent_position<<child_position;
}
void RemoveContainment::restore_data_impl(RestoreStream& p_stream)
{
   p_stream>>parent_id>>child_id>>parent_position>>child_position;
}
//
MoveChild::MoveChild()
:
   Primitive(type_MoveChild)
{
}
MoveChild::MoveChild(const Document *p_doc,Identified *p_parent,int p_old_position,int p_new_position)
:
   Primitive(type_MoveChild),
   parent_id(p_parent->get_id()),
   old_position(p_old_position),new_position(p_new_position)
{
   const Root *const r=p_doc->get_root();
   Root::IdentifiedList const children=r->child.value(p_parent);
   if(old_position<0||old_position>=children.length())
      throw UiError(qApp->translate("Primitive","Try to move non-existing child."));
   if(new_position<0||new_position>children.length())
   {
      new_position=children.length();
   }
   prepare_base(p_doc);
}
MoveChild::~MoveChild()
{
}
Primitive *MoveChild::create(unsigned int p_type,RestoreStream &p_stream)
{
   return new MoveChild;
}
UiError MoveChild::exec_impl(Document *p_doc)
{
   Identified *const parent=p_doc->lookup_object(parent_id);
   Root::IdentifiedList &children=p_doc->get_root()->child[parent];
   children.move(old_position,new_position);
   return UiError();
}
UiError MoveChild::undo_impl(Document *p_doc)
{
   Identified *const parent=p_doc->lookup_object(parent_id);
   Root::IdentifiedList &children=p_doc->get_root()->child[parent];
   children.move(new_position,old_position);
   return UiError();
}
void MoveChild::store_data_impl(QDataStream& p_stream) const
{
   p_stream<<parent_id<<old_position<<new_position;
}
void MoveChild::restore_data_impl(RestoreStream& p_stream)
{
   p_stream>>parent_id>>old_position>>new_position;
}
//
NewDataObject::NewDataObject(ModelDataObjectAdapter &p_adapter)
:
   Primitive(type_NewDataObject),
   adapter(p_adapter)
{
}
NewDataObject::NewDataObject(ModelDataObjectAdapter &p_adapter,const Document *p_doc,Identified *p_parent,int p_position)
:
   Primitive(type_NewDataObject),
   adapter(p_adapter),
   new_position(p_position)
{
   if(p_parent==0)
   {
      p_parent=p_doc->get_root()->root_group;
   }
   new_parent_id=p_parent->get_id();
   Root::IdentifiedList const children=p_doc->get_root()->child.value(p_parent);
   if(new_position<0||new_position>children.length())
   {
      new_position=children.length();
   }
   prepare_base(p_doc);
}
NewDataObject::~NewDataObject()
{
}
Primitive *NewDataObject::create(unsigned int p_type,RestoreStream &p_stream)
{
   quint32 atype;p_stream>>atype;
   ModelDataObjectAdapter *adapter=ModelDataObjectAdapter::get_adapter(atype);
   if (!adapter)
      return 0;
   return new NewDataObject(*adapter);
}
Identified *NewDataObject::get_new_object(Document *p_doc) const
{
   return p_doc->lookup_object(new_object_id);
}
UiError NewDataObject::exec_impl(Document *p_doc)
{
   Identified *new_object;
   if(get_state()==before_first)
   {
      new_object_id=p_doc->generate_id();
      new_object=adapter.create_object(0);
   }
   else
   {
      try
      {
         new_object=adapter.restore_object(new_object_data,p_doc->get_id_map());
      }
      catch(RestoreError err)
      {
         return err.get_message();
      }
      new_object_data.clear();
   }
   new_object->set_id(new_object_id);
   adapter.insert_into_root(new_object,p_doc->get_root());
   p_doc->map_object(new_object);
   Identified *const parent=p_doc->lookup_object(new_parent_id);
   p_doc->get_root()->child[parent].insert(new_position,new_object);
   p_doc->get_root()->parent[new_object].append(parent);
   return UiError();
}
UiError NewDataObject::undo_impl(Document *p_doc)
{
   Identified *const new_object=p_doc->lookup_object(new_object_id);
   Identified *const parent=p_doc->lookup_object(new_parent_id);
   if(!new_object)
      return qApp->translate("Primitive","Object not found.");
   p_doc->get_root()->child[parent].removeAt(new_position);
   if(p_doc->get_root()->child[parent].empty())
   {
      p_doc->get_root()->child.remove(parent);
   }
   p_doc->get_root()->parent.remove(new_object);
   adapter.store_object_data(new_object,new_object_data);
   adapter.remove_from_root(new_object,p_doc->get_root());
   p_doc->unmap_object(new_object);
   delete new_object;
   return UiError();
}
void NewDataObject::store_data_impl(QDataStream &p_stream) const
{
   p_stream<<quint32(adapter.get_adapter_type())<<new_object_id<<new_object_data<<new_parent_id<<new_position;
}
void NewDataObject::restore_data_impl(RestoreStream &p_stream)
{
   p_stream>>new_object_id>>new_object_data>>new_parent_id>>new_position;
}
//
DelDataObject::DelDataObject(ModelDataObjectAdapter &p_adapter)
:
   Primitive(type_DelDataObject),
   adapter(p_adapter)
{
}
DelDataObject::DelDataObject(ModelDataObjectAdapter &p_adapter,const Document *p_doc,Identified *p_object)
:
   Primitive(type_DelDataObject),
   adapter(p_adapter),
   old_object_id(p_object->get_id())
{
   if(p_object==p_doc->get_root()->root_group)
      throw UiError(qApp->translate("Primitive","Try to delete the root group."));
   UiError err=remove_from_containment.initialize(old_object_id,const_cast<Document*>(p_doc));
   if(err.failed())
      throw err;

   prepare_base(p_doc);
}
DelDataObject::~DelDataObject()
{
}
Primitive *DelDataObject::create(unsigned int p_type,RestoreStream &p_stream)
{
   quint32 atype;p_stream>>atype;
   ModelDataObjectAdapter *adapter=ModelDataObjectAdapter::get_adapter(atype);
   if(!adapter)
      return 0;
   return new DelDataObject(*adapter);
}
UiError DelDataObject::exec_impl(Document *p_doc)
{
   Identified *old_object=p_doc->lookup_object(old_object_id);
   if(!old_object)
      return qApp->translate("Primitive","Object not found.");
   UiError err=remove_from_containment.exec_impl(old_object_id,p_doc);
   if(err.failed())
      return err;
   adapter.store_object_data(old_object,old_object_data);
   adapter.remove_from_root(old_object,p_doc->get_root());
   p_doc->unmap_object(old_object);
   delete old_object;
   return err;
}
UiError DelDataObject::undo_impl(Document *p_doc)
{
   Identified *old_object;
   try
   {
      old_object=adapter.restore_object(old_object_data,p_doc->get_id_map());
   }
   catch(RestoreError err)
   {
      return err.get_message();
   }
   old_object->set_id(old_object_id);
   adapter.insert_into_root(old_object,p_doc->get_root());
   p_doc->map_object(old_object);
   UiError err=remove_from_containment.undo_impl(old_object_id,p_doc);
   if(err.failed())
   {
      p_doc->unmap_object(old_object);
      adapter.remove_from_root(old_object,p_doc->get_root());
      delete old_object;
   }
   else
   {
      old_object_data.clear();
   }
   return err;
}
void DelDataObject::store_data_impl(QDataStream &p_stream) const
{
   p_stream<<quint32(adapter.get_adapter_type())<<old_object_id<<old_object_data;
   remove_from_containment.store_data_impl(p_stream);
}
void DelDataObject::restore_data_impl(RestoreStream &p_stream)
{
   p_stream>>old_object_id>>old_object_data;
   remove_from_containment.restore_data_impl(p_stream);
}
//
SetDataObjectName::SetDataObjectName(ModelDataObjectAdapter &p_adapter)
:
   Primitive(type_SetDataObjectName),
   adapter(p_adapter)
{
}
SetDataObjectName::SetDataObjectName(ModelDataObjectAdapter &p_adapter,const Document *p_doc,Identified *p_object,QString p_new_name)
:
   Primitive(type_SetDataObjectName),
   adapter(p_adapter),
   old_name(p_adapter.get_object_name(p_object)),
   new_name(p_new_name)
{
   //FIXME: check that p_object is contained in the document?
   object_id=p_object->get_id();
   prepare_base(p_doc);
}
Primitive *SetDataObjectName::create(unsigned int p_type,RestoreStream &p_stream)
{
   quint32 atype;p_stream>>atype;
   ModelDataObjectAdapter *adapter=ModelDataObjectAdapter::get_adapter(atype);
   if(!adapter)
      return 0;
   return new SetDataObjectName(*adapter);
}
UiError SetDataObjectName::exec_impl(Document *p_doc)
{
   Identified *const object=p_doc->lookup_object(object_id);
   if(!object)
      return qApp->translate( "Primitive", "Target data object for command not found.");
   adapter.set_object_name(object,new_name);
   return UiError();
}
UiError SetDataObjectName::undo_impl(Document *p_doc)
{
   Identified *const object=p_doc->lookup_object(object_id);
   if(!object)
      return qApp->translate("Primitive","Target data object for command not found.");
   adapter.set_object_name(object,old_name);
   return UiError();
}
void SetDataObjectName::store_data_impl(QDataStream &p_stream) const
{
   p_stream<<quint32(adapter.get_adapter_type())<<object_id<<old_name<<new_name;
}
void SetDataObjectName::restore_data_impl(RestoreStream &p_stream)
{
   p_stream>>object_id>>old_name>>new_name;
}
//
RemoveParticleTemplate::RemoveParticleTemplate()
:
   Primitive(type_RemoveParticleTemplate)
{
}
RemoveParticleTemplate::RemoveParticleTemplate(const Document *p_doc,model::ParticleTemplate *p_particle_template)
:
   Primitive(type_RemoveParticleTemplate),
   pt_id(p_particle_template->get_id())
{
   prepare_base(p_doc);
}
RemoveParticleTemplate::~RemoveParticleTemplate()
{
}
Primitive *RemoveParticleTemplate::create(unsigned int p_type, RestoreStream &p_stream)
{
   return new RemoveParticleTemplate;
}
UiError RemoveParticleTemplate::exec_impl(Document *p_doc)
{
   if(get_state()==before_first)
   {
      const Identified *const pt=p_doc->lookup_object(pt_id);
      if(!pt)
         return qApp->translate("Primitive","Particle template not found.");
      for(QSet<EmitterTemplate*>::const_iterator eti=p_doc->get_root()->emitter_templates.begin();eti!=p_doc->get_root()->emitter_templates.end();++eti)
      {
         const EmitterTemplate *et=*eti;
         for(int i=0;i<et->emitter_blocks.count();++i)
         {
            if(et->emitter_blocks.at(i).particle==pt)
            {
               references_emitter.append(ReferenceAtEmitter(et->get_id(),i));
            }
         }
      }
   }
   return set_references(p_doc,0);
}
UiError RemoveParticleTemplate::undo_impl(Document *p_doc)
{
   ParticleTemplate *const pt=qobject_cast<ParticleTemplate*>(p_doc->lookup_object(pt_id));
   if(!pt)
      return qApp->translate("Primitive","Particle template not found or wrong type.");
   return set_references(p_doc,pt);
}
UiError RemoveParticleTemplate::set_references(Document *p_doc,ParticleTemplate *p_pt)
{
   for(QList<ReferenceAtEmitter>::const_iterator ri=references_emitter.begin();ri!=references_emitter.end();++ri)
   {
      EmitterTemplate *et=qobject_cast<EmitterTemplate*>(p_doc->lookup_object(ri->emitter_id));
      if(!et)
      {
         //TODO: restore already changed items
         return qApp->translate("Primitive","Target object of reference not found or of wrong type");
      }
      if(et->emitter_blocks.count()>=ri->emitter_block_index)
      {
         //TODO: restore already changed items
         return qApp->translate("Primitive","Index out of range");
      }
      et->emitter_blocks[ri->emitter_block_index].particle=p_pt;
   }
   return UiError();
}
void RemoveParticleTemplate::store_data_impl(QDataStream &p_stream) const
{
   p_stream<<pt_id<<qint32(references_emitter.size());
   for(QList<ReferenceAtEmitter>::const_iterator i=references_emitter.begin();i!=references_emitter.end();++i)
   {
      p_stream<<i->emitter_id<<i->emitter_block_index;
   }
}
void RemoveParticleTemplate::restore_data_impl(RestoreStream &p_stream)
{
   qint32 refcount;
   p_stream>>pt_id>>refcount;
   for(int i=0;i<refcount;++i)
   {
      Id id;
      int bi;
      p_stream>>id>>bi;
      references_emitter.append(ReferenceAtEmitter(id,bi));
   }
}
//
RemoveEmitterTemplate::RemoveEmitterTemplate()
:
   Primitive(type_RemoveEmitterTemplate)
{
}
RemoveEmitterTemplate::RemoveEmitterTemplate(const Document *p_doc,model::EmitterTemplate *p_emitter_template)
:
   Primitive(type_RemoveEmitterTemplate),
   et_id(p_emitter_template->get_id())
{
   prepare_base(p_doc);
}
RemoveEmitterTemplate::~RemoveEmitterTemplate()
{
}
Primitive *RemoveEmitterTemplate::create(unsigned int p_type, RestoreStream &p_stream)
{
   return new RemoveEmitterTemplate;
}
UiError RemoveEmitterTemplate::exec_impl(Document *p_doc)
{
   if(get_state()==before_first)
   {
      const Identified *et=p_doc->lookup_object(et_id);
      if(!et)
         return qApp->translate("Primitive","Emitter template not found.");
      for(QSet<EmitterTemplate*>::const_iterator eti=p_doc->get_root()->emitter_templates.begin();eti!=p_doc->get_root()->emitter_templates.end();++eti)
      {
         const EmitterTemplate *et=*eti;
         for(int i=0;i<et->emitter_blocks.count();++i)
         {
            if(et->emitter_blocks.at(i).emitter==et)
            {
               references_emitter.append(ReferenceAtEmitter(et->get_id(),i));
            }
         }
      }
      for(QSet<ParticleTemplate*>::const_iterator pti=p_doc->get_root()->particle_templates.begin();pti!=p_doc->get_root()->particle_templates.end();++pti)
      {
         const ParticleTemplate *pt=*pti;
         for(int i=0;i<pt->emitters.count();++i)
         {
            if(pt->emitters.at(i).emitter==et)
            {
               references_particle.append(ReferenceAtParticle(pt->get_id(),i));
            }
         }
      }
   }
   return set_references(p_doc,0);
}
UiError RemoveEmitterTemplate::undo_impl(Document *p_doc)
{
   EmitterTemplate *const et=qobject_cast<EmitterTemplate*>(p_doc->lookup_object(et_id));
   if(!et)
      return qApp->translate("Primitive","Emitter template not found or wrong type.");
   return set_references(p_doc,et);
}
UiError RemoveEmitterTemplate::set_references(Document *p_doc,EmitterTemplate *p_et)
{
   for(QList<ReferenceAtEmitter>::const_iterator ri=references_emitter.begin();ri!=references_emitter.end();++ri)
   {
      EmitterTemplate *const et=qobject_cast<EmitterTemplate*>(p_doc->lookup_object(ri->emitter_id));
      if(!et)
      {
         //TODO: restore already changed items
         return qApp->translate("Primitive","Target object of reference not found or of wrong type");
      }
      if(et->emitter_blocks.count()>=ri->emitter_block_index)
      {
         //TODO: restore already changed items
         return qApp->translate("Primitive","Index out of range");
      }
      et->emitter_blocks[ri->emitter_block_index].emitter=et;
   }
   for(QList<ReferenceAtParticle>::const_iterator ri=references_particle.begin();ri!=references_particle.end();++ri)
   {
      ParticleTemplate* pt=qobject_cast<ParticleTemplate*>(p_doc->lookup_object(ri->particle_id));
      if(!pt)
      {
         //TODO: restore already changed items
         return qApp->translate("Primitive","Target object of reference not found or of wrong type");
      }
      if(pt->emitters.count()>=ri->emitter_index)
      {
         //TODO: restore already changed items
         return qApp->translate("Primitive","Index out of range");
      }
      pt->emitters[ri->emitter_index].emitter=p_et;
   }
   return UiError();
}
void RemoveEmitterTemplate::store_data_impl(QDataStream &p_stream) const
{
   p_stream<<et_id<<qint32(references_emitter.size())<<qint32(references_particle.size());
   for(QList<ReferenceAtEmitter>::const_iterator i=references_emitter.begin();i!=references_emitter.end();++i)
   {
      p_stream<<i->emitter_id<<i->emitter_block_index;
   }
   for(QList<ReferenceAtParticle>::const_iterator i=references_particle.begin();i!=references_particle.end();++i)
   {
      p_stream<<i->particle_id<<i->emitter_index;
   }
}
void RemoveEmitterTemplate::restore_data_impl(RestoreStream &p_stream)
{
   qint32 erefcount,prefcount,i;
   p_stream>>et_id>>erefcount>>prefcount;
   for(i=0;i<erefcount;++i)
   {
      Id id;
      int bi;
      p_stream>>id>>bi;
      references_emitter.append(ReferenceAtEmitter(id,bi));
   }
   for(i=0;i<prefcount;++i)
   {
      Id id;
      int bi;
      p_stream>>id>>bi;
      references_particle.append(ReferenceAtParticle(id,bi));
   }
}
//
PTPrimitiveDelegate::PTPrimitiveDelegate(unsigned int p_type)
:
   PrimitiveDelegate(p_type)
{
}
//
SelectPT::SelectPT(PTPrimitiveDelegate *p_delegate)
:
   Primitive(type_SelectPT),deleg(p_delegate)
{
   Q_ASSERT(deleg);
}
SelectPT::SelectPT(const Document *p_doc,model::ParticleTemplate *p_pt,PTPrimitiveDelegate *p_delegate)
:
   Primitive(type_SelectPT),
   pt_id(p_pt->get_id()),
   deleg(p_delegate)
{
   Q_ASSERT(deleg);
   prepare_base(p_doc);
}
SelectPT::~SelectPT()
{
   delete deleg;
}
Primitive *SelectPT::create(unsigned int p_type,RestoreStream &p_stream)
{
   PrimitiveDelegate *const prim=PrimitiveDelegate::create(p_stream);
   switch(prim->get_type())
   {
   case type_SetPTVisible:
   case type_SetPTLifeTime:
   case type_SetPTDensity:
   case type_SetPTGravitationEnabled:
   case type_SetPTFrictionEnabled:
   case type_SetPTShape:
   case type_SetPTTextureFile:
   case type_SetPTTileS:
   case type_SetPTTileT:
   case type_SetPTNumTiles:
   case type_SetPTTileSpeedMode:
   case type_PTNewTimeMark:
   case type_PTRemTimeMark:
   case type_PTRenameTimeMark:
   case type_PTChangeTimeMark:
      break;
   default:
      delete prim;
      throw RestoreError(qApp->translate("Primitive","wrong type of PrimitiveDelegate while reading Primitives::SelectPT"));
   }
   return new SelectPT(static_cast<PTPrimitiveDelegate*>(prim));
}
UiError SelectPT::exec_impl(Document *p_doc)
{
   ParticleTemplate *pt=qobject_cast<ParticleTemplate*>(p_doc->lookup_object(pt_id));
   if(!pt)
      return qApp->translate("Primitive","Particle template not found or type mismatch.");
   return deleg->exec_impl(p_doc,pt,this);
}
UiError SelectPT::undo_impl(Document *p_doc)
{
   ParticleTemplate *const pt=qobject_cast<ParticleTemplate*>(p_doc->lookup_object(pt_id));
   if(!pt)
      return qApp->translate("Primitive","Particle template not found or type mismatch.");
   return deleg->undo_impl(p_doc,pt,this);
}
void SelectPT::store_data_impl(QDataStream &p_stream) const
{
   deleg->store_data(p_stream);
   p_stream<<pt_id;
}
void SelectPT::restore_data_impl(RestoreStream &p_stream)
{
   deleg->restore_data(p_stream);
   p_stream>>pt_id;
}
//
SetPTVisible::SetPTVisible():PTPrimitiveDelegate(type_SetPTVisible)
{
}
SetPTVisible::SetPTVisible(bool p_new_visible)
:
   PTPrimitiveDelegate(type_SetPTVisible),
   value(p_new_visible)
{
}
PrimitiveDelegate *SetPTVisible::create(unsigned int p_type,RestoreStream &p_stream)
{
   return new SetPTVisible;
}
UiError SetPTVisible::exec_impl(Document *p_doc,ParticleTemplate *p_pt,Primitive *p_parent)
{
   bool const tmp=p_pt->get_visible();
   p_pt->set_visible(value);
   value=tmp;
   return UiError();
}
UiError SetPTVisible::undo_impl(Document *p_doc,ParticleTemplate *p_pt,Primitive *p_parent)
{
   return exec_impl(p_doc,p_pt,p_parent);
}
void SetPTVisible::store_data_impl(QDataStream &p_stream) const
{
   p_stream<<value;
}
void SetPTVisible::restore_data_impl(RestoreStream &p_stream)
{
   p_stream>>value;
}
//
SetPTLifeTime::SetPTLifeTime() : PTPrimitiveDelegate(type_SetPTLifeTime)
{
}
SetPTLifeTime::SetPTLifeTime(RandomDouble p_new_life_time)
:
PTPrimitiveDelegate(type_SetPTLifeTime),
value(p_new_life_time)
{
   if (value.data().get_range().get_min()<=0) {
      throw(UiError(qApp->translate("Primitive","Lifetime is not allowed to be less than or equal to zero.")));
   }
}
PrimitiveDelegate *SetPTLifeTime::create(unsigned int type, RestoreStream &p_stream)
{
   return new SetPTLifeTime;
}
UiError SetPTLifeTime::exec_impl(Document *doc, ParticleTemplate *p_pt, Primitive *p_parent)
{
   const RandomDouble tmp = p_pt->get_life_time();
   p_pt->set_life_time(value);
   value = tmp;
   return UiError();
}
UiError SetPTLifeTime::undo_impl(Document *doc, ParticleTemplate *p_pt, Primitive *p_parent)
{
   return exec_impl(doc, p_pt, p_parent);
}
void SetPTLifeTime::store_data_impl(QDataStream& p_stream) const
{
   p_stream << value;
}
void SetPTLifeTime::restore_data_impl(RestoreStream& p_stream)
{
   p_stream >> value;
}
//
SetPTDensity::SetPTDensity() : PTPrimitiveDelegate(type_SetPTDensity)
{
}
SetPTDensity::SetPTDensity(float p_new_density)
:
PTPrimitiveDelegate(type_SetPTDensity),
value(p_new_density)
{
}
PrimitiveDelegate *SetPTDensity::create(unsigned int, RestoreStream &)
{
   return new SetPTDensity;
}
UiError SetPTDensity::exec_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   const float tmp = p_pt->get_density();
   p_pt->set_density(value);
   value = tmp;
   return UiError();
}
UiError SetPTDensity::undo_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   return exec_impl(doc, p_pt, p_parent);
}
void SetPTDensity::store_data_impl(QDataStream& p_stream) const
{
   p_stream << value;
}
void SetPTDensity::restore_data_impl(RestoreStream& p_stream)
{
   p_stream >> value;
}
//
SetPTGravitationEnabled::SetPTGravitationEnabled() : PTPrimitiveDelegate(type_SetPTGravitationEnabled)
{
}
SetPTGravitationEnabled::SetPTGravitationEnabled(bool p_new_gravitation_enabled)
:
PTPrimitiveDelegate(type_SetPTGravitationEnabled),
value(p_new_gravitation_enabled)
{
}
PrimitiveDelegate *SetPTGravitationEnabled::create(unsigned int, RestoreStream &)
{
   return new SetPTGravitationEnabled;
}
UiError SetPTGravitationEnabled::exec_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   const bool tmp = p_pt->get_gravitation_enabled();
   p_pt->set_gravitation_enabled(value);
   value = tmp;
   return UiError();
}
UiError SetPTGravitationEnabled::undo_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   return exec_impl(doc, p_pt, p_parent);
}
void SetPTGravitationEnabled::store_data_impl(QDataStream& p_stream) const
{
   p_stream << value;
}
void SetPTGravitationEnabled::restore_data_impl(RestoreStream& p_stream)
{
   p_stream >> value;
}
//
SetPTFrictionEnabled::SetPTFrictionEnabled() : PTPrimitiveDelegate(type_SetPTFrictionEnabled)
{
}
SetPTFrictionEnabled::SetPTFrictionEnabled(bool p_new_friction_enabled)
:
PTPrimitiveDelegate(type_SetPTFrictionEnabled),
value(p_new_friction_enabled)
{
}
PrimitiveDelegate *SetPTFrictionEnabled::create(unsigned int, RestoreStream &)
{
   return new SetPTFrictionEnabled;
}
UiError SetPTFrictionEnabled::exec_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   const bool tmp = p_pt->get_friction_enabled();
   p_pt->set_friction_enabled(value);
   value = tmp;
   return UiError();
}
UiError SetPTFrictionEnabled::undo_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   return exec_impl(doc, p_pt, p_parent);
}
void SetPTFrictionEnabled::store_data_impl(QDataStream& p_stream) const
{
   p_stream << value;
}
void SetPTFrictionEnabled::restore_data_impl(RestoreStream& p_stream)
{
   p_stream >> value;
}
//
SetPTShape::SetPTShape() : PTPrimitiveDelegate(type_SetPTShape)
{
}
SetPTShape::SetPTShape(ParticleTemplate::Shape p_new_shape)
:
PTPrimitiveDelegate(type_SetPTShape),
value(p_new_shape)
{
   //TODO:check for valid value (allowed here to throw?)
}
PrimitiveDelegate *SetPTShape::create(unsigned int, RestoreStream &)
{
   return new SetPTShape;
}
UiError SetPTShape::exec_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   const ParticleTemplate::Shape tmp = p_pt->get_shape();
   p_pt->set_shape(value);
   value = tmp;
   return UiError();
}
UiError SetPTShape::undo_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   return exec_impl(doc, p_pt, p_parent);
}
void SetPTShape::store_data_impl(QDataStream& p_stream) const
{
   p_stream << static_cast<unsigned int>(value);
}
void SetPTShape::restore_data_impl(RestoreStream& p_stream)
{
   unsigned int v;
   p_stream >> v;
   switch(v)
   {
   case ParticleTemplate::shape_point:
      value=ParticleTemplate::shape_point;
      break;
   case ParticleTemplate::shape_quad:
      value=ParticleTemplate::shape_quad;
      break;
   case ParticleTemplate::shape_quad_trianglestrip:
      value=ParticleTemplate::shape_quad_trianglestrip;
      break;
   case ParticleTemplate::shape_hexagon:
      value=ParticleTemplate::shape_hexagon;
      break;
   default:
      throw(RestoreError(qApp->translate("Primitive","wrong Shape value while reading SetPTShape")));
   }
}
//
SetPTTextureFile::SetPTTextureFile() : PTPrimitiveDelegate(type_SetPTTextureFile)
{
}
SetPTTextureFile::SetPTTextureFile(QString p_new_texture_file)
:
PTPrimitiveDelegate(type_SetPTTextureFile),
value(p_new_texture_file)
{
}
PrimitiveDelegate *SetPTTextureFile::create(unsigned int, RestoreStream &)
{
   return new SetPTTextureFile;
}
UiError SetPTTextureFile::exec_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   const QString tmp = p_pt->get_texture_file();
   p_pt->set_texture_file(value);
   value = tmp;
   return UiError();
}
UiError SetPTTextureFile::undo_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   return exec_impl(doc, p_pt, p_parent);
}
void SetPTTextureFile::store_data_impl(QDataStream& p_stream) const
{
   p_stream << value;
}
void SetPTTextureFile::restore_data_impl(RestoreStream& p_stream)
{
   p_stream >> value;
}
//
SetPTTileS::SetPTTileS() : PTPrimitiveDelegate(type_SetPTTileS)
{
}
SetPTTileS::SetPTTileS(unsigned int p_new_tile_s)
:
PTPrimitiveDelegate(type_SetPTTileS),
value(p_new_tile_s)
{
}
PrimitiveDelegate *SetPTTileS::create(unsigned int, RestoreStream &)
{
   return new SetPTTileS;
}
UiError SetPTTileS::exec_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   const unsigned int tmp = p_pt->get_tile_s();
   p_pt->set_tile_s(value);
   value = tmp;
   return UiError();
}
UiError SetPTTileS::undo_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   return exec_impl(doc, p_pt, p_parent);
}
void SetPTTileS::store_data_impl(QDataStream& p_stream) const
{
   p_stream << value;
}
void SetPTTileS::restore_data_impl(RestoreStream& p_stream)
{
   p_stream >> value;
}
//
SetPTTileT::SetPTTileT() : PTPrimitiveDelegate(type_SetPTTileT)
{
}
SetPTTileT::SetPTTileT(unsigned int p_new_tile_t)
:
PTPrimitiveDelegate(type_SetPTTileT),
value(p_new_tile_t)
{
}
PrimitiveDelegate *SetPTTileT::create(unsigned int, RestoreStream &)
{
   return new SetPTTileT;
}
UiError SetPTTileT::exec_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   const unsigned int tmp = p_pt->get_tile_t();
   p_pt->set_tile_t(value);
   value = tmp;
   return UiError();
}
UiError SetPTTileT::undo_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   return exec_impl(doc, p_pt, p_parent);
}
void SetPTTileT::store_data_impl(QDataStream& p_stream) const
{
   p_stream << value;
}
void SetPTTileT::restore_data_impl(RestoreStream& p_stream)
{
   p_stream >> value;
}
//
SetPTNumTiles::SetPTNumTiles() : PTPrimitiveDelegate(type_SetPTNumTiles)
{
}
SetPTNumTiles::SetPTNumTiles(float p_new_num_tiles)
:
PTPrimitiveDelegate(type_SetPTNumTiles),
value(p_new_num_tiles)
{
}
PrimitiveDelegate *SetPTNumTiles::create(unsigned int, RestoreStream &)
{
   return new SetPTNumTiles;
}
UiError SetPTNumTiles::exec_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   const float tmp = p_pt->get_num_tiles();
   p_pt->set_num_tiles(value);
   value = tmp;
   return UiError();
}
UiError SetPTNumTiles::undo_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   return exec_impl(doc, p_pt, p_parent);
}
void SetPTNumTiles::store_data_impl(QDataStream& p_stream) const
{
   p_stream << value;
}
void SetPTNumTiles::restore_data_impl(RestoreStream& p_stream)
{
   p_stream >> value;
}
//
SetPTTileSpeedMode::SetPTTileSpeedMode() : PTPrimitiveDelegate(type_SetPTTileSpeedMode)
{
}
SetPTTileSpeedMode::SetPTTileSpeedMode(ParticleTemplate::TileSpeedMode p_new_tile_speed_mode)
:
PTPrimitiveDelegate(type_SetPTTileSpeedMode),
value(p_new_tile_speed_mode)
{
}
PrimitiveDelegate *SetPTTileSpeedMode::create(unsigned int, RestoreStream &)
{
   return new SetPTTileSpeedMode;
}
UiError SetPTTileSpeedMode::exec_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   const ParticleTemplate::TileSpeedMode tmp = p_pt->get_tile_speed_mode();
   p_pt->set_tile_speed_mode(value);
   value = tmp;
   return UiError();
}
UiError SetPTTileSpeedMode::undo_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   return exec_impl(doc, p_pt, p_parent);
}
void SetPTTileSpeedMode::store_data_impl(QDataStream& p_stream) const
{
   p_stream << static_cast<unsigned int>(value);
}
void SetPTTileSpeedMode::restore_data_impl(RestoreStream& p_stream)
{
   unsigned int v;
   p_stream >> v;
   switch(v)
   {
   case ParticleTemplate::tile_speed_relative:
      value=ParticleTemplate::tile_speed_relative;
      break;
   case ParticleTemplate::tile_speed_absolute:
      value=ParticleTemplate::tile_speed_absolute;
      break;
   default:
      throw(RestoreError(qApp->translate("Primitive","wrong TileSpeedMode value while reading SetPTTileSpeedMode")));
   }
}
//
PTNewTimeMark::PTNewTimeMark() : PTPrimitiveDelegate(type_PTNewTimeMark)
{
}
PTNewTimeMark::PTNewTimeMark(QString p_name)
:
PTPrimitiveDelegate(type_PTNewTimeMark),
time_mark_name(p_name)
{
   if (p_name.isEmpty())
      throw UiError(qApp->translate("Primitive", "The time mark must have a non empty name."));
   new_time_mark.mode=ParticleTemplate::TimeMark::from_start;
   new_time_mark.time=RandomDouble(new RandomDouble::Constant(0));
}
PrimitiveDelegate *PTNewTimeMark::create(unsigned int, RestoreStream &)
{
   return new PTNewTimeMark;
}
UiError PTNewTimeMark::exec_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   if (p_pt->time_marks.contains(time_mark_name))
      return qApp->translate("Primitive", "Time mark '%1' already exists.").arg(time_mark_name);
   p_pt->time_marks[time_mark_name] = new_time_mark;
   return UiError();
}
UiError PTNewTimeMark::undo_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   if (!p_pt->time_marks.contains(time_mark_name))
      return qApp->translate("Primitive", "Time mark '%1' does not exist.").arg(time_mark_name);
   p_pt->time_marks.remove(time_mark_name);
   return UiError();
}
void PTNewTimeMark::store_data_impl(QDataStream& p_stream) const
{
   p_stream << time_mark_name << new_time_mark;
}
void PTNewTimeMark::restore_data_impl(RestoreStream& p_stream) 
{
   p_stream >> time_mark_name;
   p_stream >> new_time_mark;
}
//
/*class other_equal {
public:
   inline other_equal(const QString &p_val) : val(p_val) {}
   inline bool operator()(const ParticleTemplate::TimeMark &tm) {
      return tm.mode == ParticleTemplate::TimeMark::from_other && tm.other == val;
   }
private:
   const QString &val;
};
inline template<class T> QString get_time(const T &cp) {return cp.time;}*/
//
PTRemTimeMark::PTRemTimeMark() : PTPrimitiveDelegate(type_PTRemTimeMark)
{
}
PTRemTimeMark::PTRemTimeMark(QString p_name)
:
PTPrimitiveDelegate(type_PTRemTimeMark),
time_mark_name(p_name)
{
}
PrimitiveDelegate *PTRemTimeMark::create(unsigned int, RestoreStream &)
{
   return new PTRemTimeMark;
}
UiError PTRemTimeMark::exec_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   if (!p_pt->time_marks.contains(time_mark_name))
      return qApp->translate("Primitive", "Time mark '%1' does not exist.").arg(time_mark_name);
   /*QHash<QString,ParticleTemplate::TimeMark>::const_iterator tmit =
      std::find_if(p_pt->time_marks.begin(), p_pt->time_marks.end(), other_equal(p_name));
   if (tmit != p_pt->time_marks.end())
      throw UiError(qApp->translate("Primitive", "Time mark '%1' cannot be deleted because it is referenced by other elements. It is referenced by time mark '%2'.").arg(p_name, tmit.key()));*/
   QHashIterator<QString,ParticleTemplate::TimeMark> tmit(p_pt->time_marks);
   while(tmit.hasNext()) {
      tmit.next();
      if (tmit.value().mode == ParticleTemplate::TimeMark::from_other && tmit.value().other == time_mark_name)
         return(qApp->translate("Primitive", "Time mark '%1' cannot be deleted because it is referenced by other elements. It is referenced by time mark '%2'.").arg(time_mark_name, tmit.key()));
   }
   int i;
   for (i = 0; i < p_pt->color_control_points.size(); ++i) {
      if (p_pt->color_control_points[i].time == time_mark_name)
         return(qApp->translate("Primitive", "Time mark '%1' cannot be deleted because it is referenced by other elements. It is referenced by a color control point.").arg(time_mark_name));
   }
   for (i = 0; i < p_pt->alpha_control_points.size(); ++i) {
      if (p_pt->alpha_control_points[i].time == time_mark_name)
         return(qApp->translate("Primitive", "Time mark '%1' cannot be deleted because it is referenced by other elements. It is referenced by an alpha control point.").arg(time_mark_name));
   }
   for (i = 0; i < p_pt->size_control_points.size(); ++i) {
      if (p_pt->size_control_points[i].time == time_mark_name)
         return(qApp->translate("Primitive", "Time mark '%1' cannot be deleted because it is referenced by other elements. It is referenced by a size control point.").arg(time_mark_name));
   }
   for (i = 0; i < p_pt->radius_control_points.size(); ++i) {
      if (p_pt->radius_control_points[i].time == time_mark_name)
         return(qApp->translate("Primitive", "Time mark '%1' cannot be deleted because it is referenced by other elements. It is referenced by a radius control point.").arg(time_mark_name));
   }
   for (i = 0; i < p_pt->emitters.size(); ++i) {
      if (p_pt->emitters[i].time1 == time_mark_name || p_pt->emitters[i].time2 == time_mark_name)
         return(qApp->translate("Primitive", "Time mark '%1' cannot be deleted because it is referenced by other elements. It is referenced by emitter block '%2'.").arg(time_mark_name, p_pt->emitters[i].name));
   }
   if (p_parent->get_state() == Primitive::before_first) {
      removed_time_mark = p_pt->time_marks[time_mark_name];
   }
   p_pt->time_marks.remove(time_mark_name);
   return UiError();
}
UiError PTRemTimeMark::undo_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   if (p_pt->time_marks.contains(time_mark_name))
      return qApp->translate("Primitive", "Time mark '%1' does already exist.").arg(time_mark_name);
   //FIXME: reference checks?
   p_pt->time_marks[time_mark_name] = removed_time_mark;
   return UiError();
}
void PTRemTimeMark::store_data_impl(QDataStream& p_stream) const
{
   p_stream << time_mark_name << removed_time_mark;
}
void PTRemTimeMark::restore_data_impl(RestoreStream& p_stream)
{
   p_stream >> time_mark_name;
   p_stream >> removed_time_mark;
}
//
PTRenameTimeMark::PTRenameTimeMark() : PTPrimitiveDelegate(type_PTRenameTimeMark)
{
}
PTRenameTimeMark::PTRenameTimeMark(QString p_existing_name, QString p_new_name)
:
PTPrimitiveDelegate(type_PTRenameTimeMark),
current_name(p_existing_name),
other_name(p_new_name)
{
   if (other_name.isEmpty())
      throw UiError(qApp->translate("Primitive", "The time mark must have a non empty name."));
   if (current_name == other_name)
      throw UiError(qApp->translate("Primitive", "The new name is the same as the existing one."));
}
PrimitiveDelegate *PTRenameTimeMark::create(unsigned int, RestoreStream &)
{
   return new PTRenameTimeMark;
}
void PTRenameTimeMark::replace_names(ParticleTemplate *pt, QString from, QString to)
{
   QMutableHashIterator<QString,ParticleTemplate::TimeMark> tmit(pt->time_marks);
   while(tmit.hasNext()) {
      tmit.next();
      if (tmit.value().mode == ParticleTemplate::TimeMark::from_other && tmit.value().other == from)
         tmit.value().other = to;
   }
   int i;
   for (i = 0; i < pt->color_control_points.size(); ++i) {
      if (pt->color_control_points[i].time == from)
         pt->color_control_points[i].time = to;
   }
   for (i = 0; i < pt->alpha_control_points.size(); ++i) {
      if (pt->alpha_control_points[i].time == from)
         pt->alpha_control_points[i].time = to;
   }
   for (i = 0; i < pt->size_control_points.size(); ++i) {
      if (pt->size_control_points[i].time == from)
         pt->size_control_points[i].time = to;
   }
   for (i = 0; i < pt->radius_control_points.size(); ++i) {
      if (pt->radius_control_points[i].time == from)
         pt->radius_control_points[i].time = to;
   }
   for (i = 0; i < pt->emitters.size(); ++i) {
      if (pt->emitters[i].time1 == from)
         pt->emitters[i].time1 = to;
      if (pt->emitters[i].time2 == from)
         pt->emitters[i].time2 = to;
   }
}
UiError PTRenameTimeMark::exec_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   if (!p_pt->time_marks.contains(current_name))
      return qApp->translate("Primitive", "Time mark '%1' does not exist.").arg(current_name);
   if (p_pt->time_marks.contains(other_name))
      return qApp->translate("Primitive", "Time mark '%1' does already exist.").arg(other_name);
   const ParticleTemplate::TimeMark tmp = p_pt->time_marks.take(current_name);
   replace_names(p_pt, current_name, other_name);
   p_pt->time_marks[other_name] = tmp;
   std::swap(current_name, other_name);
   return UiError();
}
UiError PTRenameTimeMark::undo_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   return exec_impl(doc, p_pt, p_parent);
}
void PTRenameTimeMark::store_data_impl(QDataStream& p_stream) const
{
   p_stream << current_name << other_name;
}
void PTRenameTimeMark::restore_data_impl(RestoreStream& p_stream)
{
   p_stream >> current_name >> other_name;
   //FIXME: sanity check for argument values (new!=existing, new!=empty)?
}
//
PTChangeTimeMark::PTChangeTimeMark() : PTPrimitiveDelegate(type_PTChangeTimeMark)
{
}
PTChangeTimeMark::PTChangeTimeMark(QString p_name, const model::ParticleTemplate::TimeMark &p_new_tmark)
:
PTPrimitiveDelegate(type_PTChangeTimeMark),
name(p_name)
{
   if (p_new_tmark.mode == ParticleTemplate::TimeMark::from_other) {
      if (p_new_tmark.other == name)
         throw UiError(qApp->translate("Primitive", "The time mark can not reference itself."));
   }
   value = p_new_tmark;
}
PrimitiveDelegate *PTChangeTimeMark::create(unsigned int, RestoreStream &)
{
   return new PTChangeTimeMark;
}
UiError PTChangeTimeMark::exec_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   if (!p_pt->time_marks.contains(name))
      return(qApp->translate("Primitive", "Time mark '%1' does not exist.").arg(name));
   if (value.mode == ParticleTemplate::TimeMark::from_other) {
      if (!p_pt->time_marks.contains(value.other))
         return(qApp->translate("Primitive", "Time mark '%1' does not exist.").arg(value.other));
      if (p_pt->compute_time_mark_ancestor(value.other) == name)
         return(qApp->translate("Primitive", "The time mark can not reference itself indirectly."));
   }
   std::swap(p_pt->time_marks[name], value);
   return UiError();
}
UiError PTChangeTimeMark::undo_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   return exec_impl(doc, p_pt, p_parent);
}
void PTChangeTimeMark::store_data_impl(QDataStream& p_stream) const
{
   p_stream << value;
}
void PTChangeTimeMark::restore_data_impl(RestoreStream& p_stream)
{
   p_stream >> value;
}
//
PTNewEB::PTNewEB() : PTPrimitiveDelegate(type_PTNewEB)
{
}
PTNewEB::PTNewEB(QString p_name)
:
PTPrimitiveDelegate(type_PTNewEB)
{
   new_eb.name = p_name;
}
PrimitiveDelegate *PTNewEB::create(unsigned int, RestoreStream &)
{
   return new PTNewEB;
}
UiError PTNewEB::exec_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   //new_eb_index = p_pt->emitters.count();
   p_pt->emitters.append(new_eb);
   return UiError();
}
UiError PTNewEB::undo_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   //Q_ASSERT(new_eb_index+1 == p_pt->emitters.count());
   p_pt->emitters.removeLast();
   return UiError();
}
void PTNewEB::store_data_impl(QDataStream& p_stream) const
{
   p_stream << new_eb;
}
void PTNewEB::restore_data_impl(RestoreStream& p_stream)
{
   p_stream >> new_eb;
}
//
PTRemEB::PTRemEB() : PTPrimitiveDelegate(type_PTNewEB)
{
}
PTRemEB::PTRemEB(int p_index)
:
PTPrimitiveDelegate(type_PTRemEB), eb_index(p_index)
{
}
PrimitiveDelegate *PTRemEB::create(unsigned int, RestoreStream &)
{
   return new PTRemEB;
}
UiError PTRemEB::exec_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   if (eb_index < 0 || eb_index >= p_pt->emitters.count())
      return(qApp->translate("Primitive", "Emitter block index %1 is out of range.").arg(eb_index));
   old_eb = p_pt->emitters.at(eb_index);
   p_pt->emitters.removeAt(eb_index);
   return UiError();
}
UiError PTRemEB::undo_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   p_pt->emitters.insert(eb_index, old_eb);
   return UiError();
}
void PTRemEB::store_data_impl(QDataStream& p_stream) const
{
   p_stream << eb_index << old_eb;
}
void PTRemEB::restore_data_impl(RestoreStream& p_stream)
{
   p_stream >> eb_index;
   p_stream >> old_eb;
}
//
PTEBPrimitiveDelegate::PTEBPrimitiveDelegate(unsigned int type)
:
PrimitiveDelegate(type)
{
}
//
SelectPTEB::SelectPTEB(PTEBPrimitiveDelegate *p_delegate) : Primitive(type_SelectPTEB), deleg(p_delegate)
{
   Q_ASSERT(deleg);
}
SelectPTEB::SelectPTEB(const Document *p_doc, model::ParticleTemplate *p_pt, int p_eb_index, PTEBPrimitiveDelegate *p_delegate)
:
Primitive(type_SelectPTEB),
pt_id(p_pt->get_id()),
eb_index(p_eb_index),
deleg(p_delegate)
{
   Q_ASSERT(deleg);
   prepare_base(p_doc);
}
SelectPTEB::~SelectPTEB()
{
   delete deleg;
}
Primitive *SelectPTEB::create(unsigned int type, RestoreStream &p_stream)
{
   PrimitiveDelegate *prim = PrimitiveDelegate::create(p_stream);
   switch(prim->get_type())
   {
   case type_PTSetEBName:
   case type_PTSetEBEmitter:
   case type_PTSetEBTime1:
   case type_PTSetEBTime2:
   case type_PTSetEBIntervalMin:
   case type_PTSetEBIntervalMax:
      break;
   default:
      delete prim;
      throw RestoreError(qApp->translate("Primitive","wrong type of PrimitiveDelegate while reading Primitives::SelectPTEB"));
   }
   return new SelectPTEB(static_cast<PTEBPrimitiveDelegate*>(prim));
}
UiError SelectPTEB::exec_impl(Document *doc)
{
   ParticleTemplate *pt=qobject_cast<ParticleTemplate*>(doc->lookup_object(pt_id));
   if (!pt)
      return qApp->translate("Primitive","Particle template not found or type mismatch.");
   if (eb_index < 0 || eb_index >= pt->emitters.size())
      return qApp->translate("Primitive","Emitter block index %1 out of range in '%2'.").arg(eb_index).arg(pt->get_name());
   ParticleTemplate::EmitterBlock &eb = pt->emitters[eb_index];
   UiError err = deleg->exec_impl(doc, pt, eb, this);
   return err;
}
UiError SelectPTEB::undo_impl(Document *doc)
{
   ParticleTemplate *pt=qobject_cast<ParticleTemplate*>(doc->lookup_object(pt_id));
   if (!pt)
      return qApp->translate("Primitive","Particle template not found or type mismatch.");
   if (eb_index < 0 || eb_index >= pt->emitters.size())
      return qApp->translate("Primitive","Emitter block index %1 out of range in '%2'.").arg(eb_index).arg(pt->get_name());
   ParticleTemplate::EmitterBlock &eb = pt->emitters[eb_index];
   UiError err = deleg->undo_impl(doc, pt, eb, this);
   return err;
}
void SelectPTEB::store_data_impl(QDataStream& p_stream) const
{
   deleg->store_data(p_stream);
   p_stream << pt_id << eb_index;
}
void SelectPTEB::restore_data_impl(RestoreStream& p_stream)
{
   deleg->restore_data(p_stream);
   p_stream >> pt_id >> eb_index;
}
//
PTSetEBName::PTSetEBName(QString p_name)
:
PTEBPrimitiveDelegate(type_PTSetEBName), eb_name(p_name)
{
}
PrimitiveDelegate *PTSetEBName::create(unsigned int type, RestoreStream &p_stream)
{
   return new PTSetEBName;
}
PTSetEBName::PTSetEBName()
:
PTEBPrimitiveDelegate(type_PTSetEBName)
{
}
UiError PTSetEBName::exec_impl(Document *doc, model::ParticleTemplate *p_pt, model::ParticleTemplate::EmitterBlock &p_eb, Primitive *p_parent)
{
   std::swap(p_eb.name, eb_name);
   return UiError();
}
UiError PTSetEBName::undo_impl(Document *doc, model::ParticleTemplate *p_pt, model::ParticleTemplate::EmitterBlock &p_eb, Primitive *p_parent)
{
   return exec_impl(doc, p_pt, p_eb, p_parent);
}
void PTSetEBName::store_data_impl(QDataStream& p_stream) const
{
   p_stream << eb_name;
}
void PTSetEBName::restore_data_impl(RestoreStream& p_stream)
{
   p_stream >> eb_name;
}
//
PTSetEBEmitter::PTSetEBEmitter(model::EmitterTemplate *p_emitter)
:
PTEBPrimitiveDelegate(type_PTSetEBEmitter), et_id(p_emitter->get_id())
{
}
PrimitiveDelegate *PTSetEBEmitter::create(unsigned int type, RestoreStream &p_stream)
{
   return new PTSetEBEmitter;
}
PTSetEBEmitter::PTSetEBEmitter()
:
PTEBPrimitiveDelegate(type_PTSetEBEmitter)
{
}
UiError PTSetEBEmitter::exec_impl(Document *doc, model::ParticleTemplate *p_pt, model::ParticleTemplate::EmitterBlock &p_eb, Primitive *p_parent)
{
   EmitterTemplate *et = qobject_cast<EmitterTemplate*>(doc->lookup_object(et_id));
   if (!et)
      return qApp->translate("Primitive","Emitter template not found or wrong type");
   et_id = p_eb.emitter->get_id();
   p_eb.emitter = et;
   return UiError();
}
UiError PTSetEBEmitter::undo_impl(Document *doc, model::ParticleTemplate *p_pt, model::ParticleTemplate::EmitterBlock &p_eb, Primitive *p_parent)
{
   return exec_impl(doc, p_pt, p_eb, p_parent);
}
void PTSetEBEmitter::store_data_impl(QDataStream& p_stream) const
{
   p_stream << et_id;
}
void PTSetEBEmitter::restore_data_impl(RestoreStream& p_stream)
{
   p_stream >> et_id;
}
//
PTSetEBTime1::PTSetEBTime1(QString p_time1)
:
PTEBPrimitiveDelegate(type_PTSetEBTime1), time1(p_time1)
{
   if (time1.isEmpty())
      throw UiError(qApp->translate("Primitive","Time name can not be empty."));
}
PrimitiveDelegate *PTSetEBTime1::create(unsigned int type, RestoreStream &p_stream)
{
   return new PTSetEBTime1;
}
PTSetEBTime1::PTSetEBTime1()
:
PTEBPrimitiveDelegate(type_PTSetEBTime1)
{
}
UiError PTSetEBTime1::exec_impl(Document *doc, model::ParticleTemplate *p_pt, model::ParticleTemplate::EmitterBlock &p_eb, Primitive *p_parent)
{
   if (!p_pt->time_marks.contains(time1))
      return qApp->translate("Primitive","Time mark '%1' does not exist.").arg(time1);
   std::swap(p_eb.time1, time1);
   return UiError();
}
UiError PTSetEBTime1::undo_impl(Document *doc, model::ParticleTemplate *p_pt, model::ParticleTemplate::EmitterBlock &p_eb, Primitive *p_parent)
{
   return exec_impl(doc, p_pt, p_eb, p_parent);
}
void PTSetEBTime1::store_data_impl(QDataStream& p_stream) const
{
   p_stream << time1;
}
void PTSetEBTime1::restore_data_impl(RestoreStream& p_stream)
{
   p_stream >> time1;
}
//
PTSetEBTime2::PTSetEBTime2(QString p_time2)
:
PTEBPrimitiveDelegate(type_PTSetEBTime2), time2(p_time2)
{
}
PrimitiveDelegate *PTSetEBTime2::create(unsigned int type, RestoreStream &p_stream)
{
   return new PTSetEBTime2;
}
PTSetEBTime2::PTSetEBTime2()
:
PTEBPrimitiveDelegate(type_PTSetEBTime2)
{
}
UiError PTSetEBTime2::exec_impl(Document *doc, model::ParticleTemplate *p_pt, model::ParticleTemplate::EmitterBlock &p_eb, Primitive *p_parent)
{
   if (!time2.isEmpty() && !p_pt->time_marks.contains(time2))
      return qApp->translate("Primitive","Time mark '%1' does not exist.").arg(time2);
   std::swap(p_eb.time2, time2);
   return UiError();
}
UiError PTSetEBTime2::undo_impl(Document *doc, model::ParticleTemplate *p_pt, model::ParticleTemplate::EmitterBlock &p_eb, Primitive *p_parent)
{
   return exec_impl(doc, p_pt, p_eb, p_parent);
}
void PTSetEBTime2::store_data_impl(QDataStream& p_stream) const
{
   p_stream << time2;
}
void PTSetEBTime2::restore_data_impl(RestoreStream& p_stream)
{
   p_stream >> time2;
}
//
PTSetEBIntervalMin::PTSetEBIntervalMin(double imin)
:
PTEBPrimitiveDelegate(type_PTSetEBIntervalMin), interval_min(imin)
{
}
PrimitiveDelegate *PTSetEBIntervalMin::create(unsigned int type, RestoreStream &p_stream)
{
   return new PTSetEBIntervalMin;
}
PTSetEBIntervalMin::PTSetEBIntervalMin()
:
PTEBPrimitiveDelegate(type_PTSetEBIntervalMin)
{
}
UiError PTSetEBIntervalMin::exec_impl(Document *doc, model::ParticleTemplate *p_pt, model::ParticleTemplate::EmitterBlock &p_eb, Primitive *p_parent)
{
   if (p_eb.interval_max <= interval_min)
      return qApp->translate("Primitive","Interval minimum must be less than the maximum.");
   std::swap(p_eb.interval_min, interval_min);
   return UiError();
}
UiError PTSetEBIntervalMin::undo_impl(Document *doc, model::ParticleTemplate *p_pt, model::ParticleTemplate::EmitterBlock &p_eb, Primitive *p_parent)
{
   return exec_impl(doc, p_pt, p_eb, p_parent);
}
void PTSetEBIntervalMin::store_data_impl(QDataStream& p_stream) const
{
   p_stream << interval_min;
}
void PTSetEBIntervalMin::restore_data_impl(RestoreStream& p_stream)
{
   p_stream >> interval_min;
}
//
PTSetEBIntervalMax::PTSetEBIntervalMax(double imax)
:
PTEBPrimitiveDelegate(type_PTSetEBIntervalMax), interval_max(imax)
{
}
PrimitiveDelegate *PTSetEBIntervalMax::create(unsigned int type, RestoreStream &p_stream)
{
   return new PTSetEBIntervalMax;
}
PTSetEBIntervalMax::PTSetEBIntervalMax()
:
PTEBPrimitiveDelegate(type_PTSetEBIntervalMax)
{
}
UiError PTSetEBIntervalMax::exec_impl(Document *doc, model::ParticleTemplate *p_pt, model::ParticleTemplate::EmitterBlock &p_eb, Primitive *p_parent)
{
   if (p_eb.interval_min >= interval_max)
      return qApp->translate("Primitive","Interval minimum must be less than the maximum.");
   std::swap(p_eb.interval_max, interval_max);
   return UiError();
}
UiError PTSetEBIntervalMax::undo_impl(Document *doc, model::ParticleTemplate *p_pt, model::ParticleTemplate::EmitterBlock &p_eb, Primitive *p_parent)
{
   return exec_impl(doc, p_pt, p_eb, p_parent);
}
void PTSetEBIntervalMax::store_data_impl(QDataStream& p_stream) const
{
   p_stream << interval_max;
}
void PTSetEBIntervalMax::restore_data_impl(RestoreStream& p_stream)
{
   p_stream >> interval_max;
}
//
PTColorCPSetConst::PTColorCPSetConst() : PTPrimitiveDelegate(type_PTColorCPSetConst)
{
}
PTColorCPSetConst::PTColorCPSetConst(const RandomColor &p_value)
:
PTPrimitiveDelegate(type_PTColorCPSetConst), new_value(p_value)
{
}
PrimitiveDelegate *PTColorCPSetConst::create(unsigned int, RestoreStream &)
{
   return new PTColorCPSetConst;
}
UiError PTColorCPSetConst::exec_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   if (p_parent->get_state() == Primitive::before_first) {
      old_points = p_pt->color_control_points;
   }
   p_pt->color_control_points.empty();
   p_pt->color_control_points.append(ParticleTemplate::ColorControlPoint("",new_value));
   return UiError();
}
UiError PTColorCPSetConst::undo_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   p_pt->color_control_points = old_points;
   return UiError();
}
void PTColorCPSetConst::store_data_impl(QDataStream& p_stream) const
{
   p_stream << old_points << new_value;
}
void PTColorCPSetConst::restore_data_impl(RestoreStream& p_stream)
{
   p_stream >> old_points >> new_value;
}
//
PTColorCPSetLine::PTColorCPSetLine() : PTPrimitiveDelegate(type_PTColorCPSetLine)
{
}
PTColorCPSetLine::PTColorCPSetLine(const RandomColor &p_value_start, const RandomColor &p_value_end)
:
PTPrimitiveDelegate(type_PTColorCPSetLine), new_value_start(p_value_start), new_value_end(p_value_end)
{
}
PrimitiveDelegate *PTColorCPSetLine::create(unsigned int, RestoreStream &)
{
   return new PTColorCPSetLine;
}
UiError PTColorCPSetLine::exec_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   if (p_parent->get_state() == Primitive::before_first) {
      old_points = p_pt->color_control_points;
   }
   p_pt->color_control_points.empty();
   p_pt->color_control_points.append(ParticleTemplate::ColorControlPoint("",new_value_start));
   p_pt->color_control_points.append(ParticleTemplate::ColorControlPoint("",new_value_end));
   return UiError();
}
UiError PTColorCPSetLine::undo_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   p_pt->color_control_points = old_points;
   return UiError();
}
void PTColorCPSetLine::store_data_impl(QDataStream& p_stream) const
{
   p_stream << old_points << new_value_start << new_value_end;
}
void PTColorCPSetLine::restore_data_impl(RestoreStream& p_stream)
{
   p_stream >> old_points >> new_value_start >> new_value_end;
}
//
PTNewColorCP::PTNewColorCP() : PTPrimitiveDelegate(type_PTNewColorCP)
{
}
PTNewColorCP::PTNewColorCP(const model::ParticleTemplate::ColorControlPoint &p_new_cp, int p_index)
:
PTPrimitiveDelegate(type_PTNewColorCP), new_cp(p_new_cp), cp_index(p_index)
{
   if (new_cp.time.isEmpty())
      throw UiError(qApp->translate("Primitive","Control point must have a time."));
}
PrimitiveDelegate *PTNewColorCP::create(unsigned int, RestoreStream &)
{
   return new PTNewColorCP;
}
UiError PTNewColorCP::exec_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   if (cp_index <= 0 || cp_index >= p_pt->color_control_points.size()-1)
      return qApp->translate("Primitive","Invalid control point index.");
   if (!p_pt->time_marks.contains(new_cp.time))
      return qApp->translate("Primitive","Time mark '%1' of control point does not exist.").arg(new_cp.time);
   p_pt->color_control_points.insert(cp_index, new_cp);
   return UiError();
}
UiError PTNewColorCP::undo_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   p_pt->color_control_points.removeAt(cp_index);
   return UiError();
}
void PTNewColorCP::store_data_impl(QDataStream& p_stream) const
{
   p_stream << new_cp << cp_index;
}
void PTNewColorCP::restore_data_impl(RestoreStream& p_stream)
{
   p_stream >> new_cp >> cp_index;
}
//
PTRemColorCP::PTRemColorCP() : PTPrimitiveDelegate(type_PTRemColorCP)
{
}
PTRemColorCP::PTRemColorCP(int p_index)
:
PTPrimitiveDelegate(type_PTRemColorCP), cp_index(p_index)
{
}
PrimitiveDelegate *PTRemColorCP::create(unsigned int, RestoreStream &)
{
   return new PTRemColorCP;
}
UiError PTRemColorCP::exec_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   if (cp_index <= 0 || cp_index >= p_pt->color_control_points.size()-1)
      return qApp->translate("Primitive","Invalid control point index.");
   if (p_parent->get_state() == Primitive::before_first) {
      old_cp = p_pt->color_control_points.takeAt(cp_index);
   } else {
      p_pt->color_control_points.removeAt(cp_index);
   }
   return UiError();
}
UiError PTRemColorCP::undo_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   p_pt->color_control_points.insert(cp_index, old_cp);
   return UiError();
}
void PTRemColorCP::store_data_impl(QDataStream& p_stream) const
{
   p_stream << old_cp << cp_index;
}
void PTRemColorCP::restore_data_impl(RestoreStream& p_stream)
{
   p_stream >> old_cp >> cp_index;
}
//
PTSetColorCPValue::PTSetColorCPValue() : PTPrimitiveDelegate(type_PTSetColorCPValue)
{
}
PTSetColorCPValue::PTSetColorCPValue(int p_index, const RandomColor &p_value)
:
PTPrimitiveDelegate(type_PTSetColorCPValue), value(p_value), cp_index(p_index)
{
}
PrimitiveDelegate *PTSetColorCPValue::create(unsigned int, RestoreStream &)
{
   return new PTSetColorCPValue;
}
UiError PTSetColorCPValue::exec_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   if (cp_index < 0 || cp_index > p_pt->color_control_points.size()-1)
      return qApp->translate("Primitive","Invalid control point index.");
   std::swap(p_pt->color_control_points[cp_index].color, value);
   return UiError();
}
UiError PTSetColorCPValue::undo_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   return exec_impl(doc, p_pt, p_parent);
}
void PTSetColorCPValue::store_data_impl(QDataStream& p_stream) const
{
   p_stream << value << cp_index;
}
void PTSetColorCPValue::restore_data_impl(RestoreStream& p_stream)
{
   p_stream >> value >> cp_index;
}
//
PTAlphaCPSetConst::PTAlphaCPSetConst() : PTPrimitiveDelegate(type_PTAlphaCPSetConst)
{
}
PTAlphaCPSetConst::PTAlphaCPSetConst(const RandomDouble &p_value)
:
PTPrimitiveDelegate(type_PTAlphaCPSetConst), new_value(p_value)
{
}
PrimitiveDelegate *PTAlphaCPSetConst::create(unsigned int, RestoreStream &)
{
   return new PTAlphaCPSetConst;
}
UiError PTAlphaCPSetConst::exec_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   if (p_parent->get_state() == Primitive::before_first) {
      old_points = p_pt->alpha_control_points;
   }
   p_pt->alpha_control_points.empty();
   p_pt->alpha_control_points.append(ParticleTemplate::FloatControlPoint("",new_value));
   return UiError();
}
UiError PTAlphaCPSetConst::undo_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   p_pt->alpha_control_points = old_points;
   return UiError();
}
void PTAlphaCPSetConst::store_data_impl(QDataStream& p_stream) const
{
   p_stream << old_points << new_value;
}
void PTAlphaCPSetConst::restore_data_impl(RestoreStream& p_stream)
{
   p_stream >> old_points >> new_value;
}
//
PTAlphaCPSetLine::PTAlphaCPSetLine() : PTPrimitiveDelegate(type_PTAlphaCPSetLine)
{
}
PTAlphaCPSetLine::PTAlphaCPSetLine(const RandomDouble &p_value_start, const RandomDouble &p_value_end)
:
PTPrimitiveDelegate(type_PTAlphaCPSetLine), new_value_start(p_value_start), new_value_end(p_value_end)
{
}
PrimitiveDelegate *PTAlphaCPSetLine::create(unsigned int, RestoreStream &)
{
   return new PTAlphaCPSetLine;
}
UiError PTAlphaCPSetLine::exec_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   if (p_parent->get_state() == Primitive::before_first) {
      old_points = p_pt->alpha_control_points;
   }
   p_pt->alpha_control_points.empty();
   p_pt->alpha_control_points.append(ParticleTemplate::FloatControlPoint("",new_value_start));
   p_pt->alpha_control_points.append(ParticleTemplate::FloatControlPoint("",new_value_end));
   return UiError();
}
UiError PTAlphaCPSetLine::undo_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   p_pt->alpha_control_points = old_points;
   return UiError();
}
void PTAlphaCPSetLine::store_data_impl(QDataStream& p_stream) const
{
   p_stream << old_points << new_value_start << new_value_end;
}
void PTAlphaCPSetLine::restore_data_impl(RestoreStream& p_stream)
{
   p_stream >> old_points >> new_value_start >> new_value_end;
}
//
PTNewAlphaCP::PTNewAlphaCP() : PTPrimitiveDelegate(type_PTNewAlphaCP)
{
}
PTNewAlphaCP::PTNewAlphaCP(const model::ParticleTemplate::FloatControlPoint &p_new_cp, int p_index)
:
PTPrimitiveDelegate(type_PTNewAlphaCP), new_cp(p_new_cp), cp_index(p_index)
{
   if (new_cp.time.isEmpty())
      throw UiError(qApp->translate("Primitive","Control point must have a time."));
}
PrimitiveDelegate *PTNewAlphaCP::create(unsigned int, RestoreStream &)
{
   return new PTNewAlphaCP;
}
UiError PTNewAlphaCP::exec_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   if (cp_index <= 0 || cp_index >= p_pt->alpha_control_points.size()-1)
      return qApp->translate("Primitive","Invalid control point index.");
   if (!p_pt->time_marks.contains(new_cp.time))
      return qApp->translate("Primitive","Time mark '%1' of control point does not exist.").arg(new_cp.time);
   p_pt->alpha_control_points.insert(cp_index, new_cp);
   return UiError();
}
UiError PTNewAlphaCP::undo_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   p_pt->alpha_control_points.removeAt(cp_index);
   return UiError();
}
void PTNewAlphaCP::store_data_impl(QDataStream& p_stream) const
{
   p_stream << new_cp << cp_index;
}
void PTNewAlphaCP::restore_data_impl(RestoreStream& p_stream)
{
   p_stream >> new_cp >> cp_index;
}
//
PTRemAlphaCP::PTRemAlphaCP() : PTPrimitiveDelegate(type_PTRemAlphaCP)
{
}
PTRemAlphaCP::PTRemAlphaCP(int p_index)
:
PTPrimitiveDelegate(type_PTRemAlphaCP), cp_index(p_index)
{
}
PrimitiveDelegate *PTRemAlphaCP::create(unsigned int, RestoreStream &)
{
   return new PTRemAlphaCP;
}
UiError PTRemAlphaCP::exec_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   if (cp_index <= 0 || cp_index >= p_pt->alpha_control_points.size()-1)
      return qApp->translate("Primitive","Invalid control point index.");
   if (p_parent->get_state() == Primitive::before_first) {
      old_cp = p_pt->alpha_control_points.takeAt(cp_index);
   } else {
      p_pt->alpha_control_points.removeAt(cp_index);
   }
   return UiError();
}
UiError PTRemAlphaCP::undo_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   p_pt->alpha_control_points.insert(cp_index, old_cp);
   return UiError();
}
void PTRemAlphaCP::store_data_impl(QDataStream& p_stream) const
{
   p_stream << old_cp << cp_index;
}
void PTRemAlphaCP::restore_data_impl(RestoreStream& p_stream)
{
   p_stream >> old_cp >> cp_index;
}
//
PTSetAlphaCPValue::PTSetAlphaCPValue() : PTPrimitiveDelegate(type_PTSetAlphaCPValue)
{
}
PTSetAlphaCPValue::PTSetAlphaCPValue(int p_index, const RandomDouble &p_value)
:
PTPrimitiveDelegate(type_PTSetAlphaCPValue), value(p_value), cp_index(p_index)
{
}
PrimitiveDelegate *PTSetAlphaCPValue::create(unsigned int, RestoreStream &)
{
   return new PTSetAlphaCPValue;
}
UiError PTSetAlphaCPValue::exec_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   if (cp_index < 0 || cp_index > p_pt->alpha_control_points.size()-1)
      return qApp->translate("Primitive","Invalid control point index.");
   std::swap(p_pt->alpha_control_points[cp_index].value, value);
   return UiError();
}
UiError PTSetAlphaCPValue::undo_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   return exec_impl(doc, p_pt, p_parent);
}
void PTSetAlphaCPValue::store_data_impl(QDataStream& p_stream) const
{
   p_stream << value << cp_index;
}
void PTSetAlphaCPValue::restore_data_impl(RestoreStream& p_stream)
{
   p_stream >> value >> cp_index;
}
//
PTSizeCPSetConst::PTSizeCPSetConst() : PTPrimitiveDelegate(type_PTSizeCPSetConst)
{
}
PTSizeCPSetConst::PTSizeCPSetConst(const RandomDouble &p_value)
:
PTPrimitiveDelegate(type_PTSizeCPSetConst), new_value(p_value)
{
}
PrimitiveDelegate *PTSizeCPSetConst::create(unsigned int, RestoreStream &)
{
   return new PTSizeCPSetConst;
}
UiError PTSizeCPSetConst::exec_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   if (p_parent->get_state() == Primitive::before_first) {
      old_points = p_pt->size_control_points;
   }
   p_pt->size_control_points.empty();
   p_pt->size_control_points.append(ParticleTemplate::FloatControlPoint("",new_value));
   return UiError();
}
UiError PTSizeCPSetConst::undo_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   p_pt->size_control_points = old_points;
   return UiError();
}
void PTSizeCPSetConst::store_data_impl(QDataStream& p_stream) const
{
   p_stream << old_points << new_value;
}
void PTSizeCPSetConst::restore_data_impl(RestoreStream& p_stream)
{
   p_stream >> old_points >> new_value;
}
//
PTSizeCPSetLine::PTSizeCPSetLine() : PTPrimitiveDelegate(type_PTSizeCPSetLine)
{
}
PTSizeCPSetLine::PTSizeCPSetLine(const RandomDouble &p_value_start, const RandomDouble &p_value_end)
:
PTPrimitiveDelegate(type_PTSizeCPSetLine), new_value_start(p_value_start), new_value_end(p_value_end)
{
}
PrimitiveDelegate *PTSizeCPSetLine::create(unsigned int, RestoreStream &)
{
   return new PTSizeCPSetLine;
}
UiError PTSizeCPSetLine::exec_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   if (p_parent->get_state() == Primitive::before_first) {
      old_points = p_pt->size_control_points;
   }
   p_pt->size_control_points.empty();
   p_pt->size_control_points.append(ParticleTemplate::FloatControlPoint("",new_value_start));
   p_pt->size_control_points.append(ParticleTemplate::FloatControlPoint("",new_value_end));
   return UiError();
}
UiError PTSizeCPSetLine::undo_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   p_pt->size_control_points = old_points;
   return UiError();
}
void PTSizeCPSetLine::store_data_impl(QDataStream& p_stream) const
{
   p_stream << old_points << new_value_start << new_value_end;
}
void PTSizeCPSetLine::restore_data_impl(RestoreStream& p_stream)
{
   p_stream >> old_points >> new_value_start >> new_value_end;
}
//
PTNewSizeCP::PTNewSizeCP() : PTPrimitiveDelegate(type_PTNewSizeCP)
{
}
PTNewSizeCP::PTNewSizeCP(const model::ParticleTemplate::FloatControlPoint &p_new_cp, int p_index)
:
PTPrimitiveDelegate(type_PTNewSizeCP), new_cp(p_new_cp), cp_index(p_index)
{
   if (new_cp.time.isEmpty())
      throw UiError(qApp->translate("Primitive","Control point must have a time."));
}
PrimitiveDelegate *PTNewSizeCP::create(unsigned int, RestoreStream &)
{
   return new PTNewSizeCP;
}
UiError PTNewSizeCP::exec_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   if (cp_index <= 0 || cp_index >= p_pt->size_control_points.size()-1)
      return qApp->translate("Primitive","Invalid control point index.");
   if (!p_pt->time_marks.contains(new_cp.time))
      return qApp->translate("Primitive","Time mark '%1' of control point does not exist.").arg(new_cp.time);
   p_pt->size_control_points.insert(cp_index, new_cp);
   return UiError();
}
UiError PTNewSizeCP::undo_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   p_pt->size_control_points.removeAt(cp_index);
   return UiError();
}
void PTNewSizeCP::store_data_impl(QDataStream& p_stream) const
{
   p_stream << new_cp << cp_index;
}
void PTNewSizeCP::restore_data_impl(RestoreStream& p_stream)
{
   p_stream >> new_cp >> cp_index;
}
//
PTRemSizeCP::PTRemSizeCP() : PTPrimitiveDelegate(type_PTRemSizeCP)
{
}
PTRemSizeCP::PTRemSizeCP(int p_index)
:
PTPrimitiveDelegate(type_PTRemSizeCP), cp_index(p_index)
{
}
PrimitiveDelegate *PTRemSizeCP::create(unsigned int, RestoreStream &)
{
   return new PTRemSizeCP;
}
UiError PTRemSizeCP::exec_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   if (cp_index <= 0 || cp_index >= p_pt->size_control_points.size()-1)
      return qApp->translate("Primitive","Invalid control point index.");
   if (p_parent->get_state() == Primitive::before_first) {
      old_cp = p_pt->size_control_points.takeAt(cp_index);
   } else {
      p_pt->size_control_points.removeAt(cp_index);
   }
   return UiError();
}
UiError PTRemSizeCP::undo_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   p_pt->size_control_points.insert(cp_index, old_cp);
   return UiError();
}
void PTRemSizeCP::store_data_impl(QDataStream& p_stream) const
{
   p_stream << old_cp << cp_index;
}
void PTRemSizeCP::restore_data_impl(RestoreStream& p_stream)
{
   p_stream >> old_cp >> cp_index;
}
//
PTSetSizeCPValue::PTSetSizeCPValue() : PTPrimitiveDelegate(type_PTSetSizeCPValue)
{
}
PTSetSizeCPValue::PTSetSizeCPValue(int p_index, const RandomDouble &p_value)
:
PTPrimitiveDelegate(type_PTSetSizeCPValue), value(p_value), cp_index(p_index)
{
}
PrimitiveDelegate *PTSetSizeCPValue::create(unsigned int, RestoreStream &)
{
   return new PTSetSizeCPValue;
}
UiError PTSetSizeCPValue::exec_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   if (cp_index < 0 || cp_index > p_pt->size_control_points.size()-1)
      return qApp->translate("Primitive","Invalid control point index.");
   std::swap(p_pt->size_control_points[cp_index].value, value);
   return UiError();
}
UiError PTSetSizeCPValue::undo_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   return exec_impl(doc, p_pt, p_parent);
}
void PTSetSizeCPValue::store_data_impl(QDataStream& p_stream) const
{
   p_stream << value << cp_index;
}
void PTSetSizeCPValue::restore_data_impl(RestoreStream& p_stream)
{
   p_stream >> value >> cp_index;
}
//
PTRadiusCPSetConst::PTRadiusCPSetConst() : PTPrimitiveDelegate(type_PTRadiusCPSetConst)
{
}
PTRadiusCPSetConst::PTRadiusCPSetConst(const RandomDouble &p_value)
:
PTPrimitiveDelegate(type_PTRadiusCPSetConst), new_value(p_value)
{
}
PrimitiveDelegate *PTRadiusCPSetConst::create(unsigned int, RestoreStream &)
{
   return new PTRadiusCPSetConst;
}
UiError PTRadiusCPSetConst::exec_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   if (p_parent->get_state() == Primitive::before_first) {
      old_points = p_pt->radius_control_points;
   }
   p_pt->radius_control_points.empty();
   p_pt->radius_control_points.append(ParticleTemplate::FloatControlPoint("",new_value));
   return UiError();
}
UiError PTRadiusCPSetConst::undo_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   p_pt->radius_control_points = old_points;
   return UiError();
}
void PTRadiusCPSetConst::store_data_impl(QDataStream& p_stream) const
{
   p_stream << old_points << new_value;
}
void PTRadiusCPSetConst::restore_data_impl(RestoreStream& p_stream)
{
   p_stream >> old_points >> new_value;
}
//
PTRadiusCPSetLine::PTRadiusCPSetLine() : PTPrimitiveDelegate(type_PTRadiusCPSetLine)
{
}
PTRadiusCPSetLine::PTRadiusCPSetLine(const RandomDouble &p_value_start, const RandomDouble &p_value_end)
:
PTPrimitiveDelegate(type_PTRadiusCPSetLine), new_value_start(p_value_start), new_value_end(p_value_end)
{
}
PrimitiveDelegate *PTRadiusCPSetLine::create(unsigned int, RestoreStream &)
{
   return new PTRadiusCPSetLine;
}
UiError PTRadiusCPSetLine::exec_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   if (p_parent->get_state() == Primitive::before_first) {
      old_points = p_pt->radius_control_points;
   }
   p_pt->radius_control_points.empty();
   p_pt->radius_control_points.append(ParticleTemplate::FloatControlPoint("",new_value_start));
   p_pt->radius_control_points.append(ParticleTemplate::FloatControlPoint("",new_value_end));
   return UiError();
}
UiError PTRadiusCPSetLine::undo_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   p_pt->radius_control_points = old_points;
   return UiError();
}
void PTRadiusCPSetLine::store_data_impl(QDataStream& p_stream) const
{
   p_stream << old_points << new_value_start << new_value_end;
}
void PTRadiusCPSetLine::restore_data_impl(RestoreStream& p_stream)
{
   p_stream >> old_points >> new_value_start >> new_value_end;
}
//
PTNewRadiusCP::PTNewRadiusCP() : PTPrimitiveDelegate(type_PTNewRadiusCP)
{
}
PTNewRadiusCP::PTNewRadiusCP(const model::ParticleTemplate::FloatControlPoint &p_new_cp, int p_index)
:
PTPrimitiveDelegate(type_PTNewRadiusCP), new_cp(p_new_cp), cp_index(p_index)
{
   if (new_cp.time.isEmpty())
      throw UiError(qApp->translate("Primitive","Control point must have a time."));
}
PrimitiveDelegate *PTNewRadiusCP::create(unsigned int, RestoreStream &)
{
   return new PTNewRadiusCP;
}
UiError PTNewRadiusCP::exec_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   if (cp_index <= 0 || cp_index >= p_pt->radius_control_points.size()-1)
      return qApp->translate("Primitive","Invalid control point index.");
   if (!p_pt->time_marks.contains(new_cp.time))
      return qApp->translate("Primitive","Time mark '%1' of control point does not exist.").arg(new_cp.time);
   p_pt->radius_control_points.insert(cp_index, new_cp);
   return UiError();
}
UiError PTNewRadiusCP::undo_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   p_pt->radius_control_points.removeAt(cp_index);
   return UiError();
}
void PTNewRadiusCP::store_data_impl(QDataStream& p_stream) const
{
   p_stream << new_cp << cp_index;
}
void PTNewRadiusCP::restore_data_impl(RestoreStream& p_stream)
{
   p_stream >> new_cp >> cp_index;
}
//
PTRemRadiusCP::PTRemRadiusCP() : PTPrimitiveDelegate(type_PTRemRadiusCP)
{
}
PTRemRadiusCP::PTRemRadiusCP(int p_index)
:
PTPrimitiveDelegate(type_PTRemRadiusCP), cp_index(p_index)
{
}
PrimitiveDelegate *PTRemRadiusCP::create(unsigned int, RestoreStream &)
{
   return new PTRemRadiusCP;
}
UiError PTRemRadiusCP::exec_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   if (cp_index <= 0 || cp_index >= p_pt->radius_control_points.size()-1)
      return qApp->translate("Primitive","Invalid control point index.");
   if (p_parent->get_state() == Primitive::before_first) {
      old_cp = p_pt->radius_control_points.takeAt(cp_index);
   } else {
      p_pt->radius_control_points.removeAt(cp_index);
   }
   return UiError();
}
UiError PTRemRadiusCP::undo_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   p_pt->radius_control_points.insert(cp_index, old_cp);
   return UiError();
}
void PTRemRadiusCP::store_data_impl(QDataStream& p_stream) const
{
   p_stream << old_cp << cp_index;
}
void PTRemRadiusCP::restore_data_impl(RestoreStream& p_stream)
{
   p_stream >> old_cp >> cp_index;
}
//
PTSetRadiusCPValue::PTSetRadiusCPValue() : PTPrimitiveDelegate(type_PTSetRadiusCPValue)
{
}
PTSetRadiusCPValue::PTSetRadiusCPValue(int p_index, const RandomDouble &p_value)
:
PTPrimitiveDelegate(type_PTSetRadiusCPValue), value(p_value), cp_index(p_index)
{
}
PrimitiveDelegate *PTSetRadiusCPValue::create(unsigned int, RestoreStream &)
{
   return new PTSetRadiusCPValue;
}
UiError PTSetRadiusCPValue::exec_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   if (cp_index < 0 || cp_index > p_pt->radius_control_points.size()-1)
      return qApp->translate("Primitive","Invalid control point index.");
   std::swap(p_pt->radius_control_points[cp_index].value, value);
   return UiError();
}
UiError PTSetRadiusCPValue::undo_impl(Document *doc, model::ParticleTemplate *p_pt, Primitive *p_parent)
{
   return exec_impl(doc, p_pt, p_parent);
}
void PTSetRadiusCPValue::store_data_impl(QDataStream& p_stream) const
{
   p_stream << value << cp_index;
}
void PTSetRadiusCPValue::restore_data_impl(RestoreStream& p_stream)
{
   p_stream >> value >> cp_index;
}
//
ETEBPrimitiveDelegate::ETEBPrimitiveDelegate(unsigned int type)
:
PrimitiveDelegate(type)
{
}
//
SelectETEB::SelectETEB(ETEBPrimitiveDelegate *p_delegate) : Primitive(type_SelectETEB), deleg(p_delegate)
{
   Q_ASSERT(deleg);
}
SelectETEB::SelectETEB(const Document *p_doc, model::EmitterTemplate *p_et, int p_eb_index, ETEBPrimitiveDelegate *p_delegate)
:
Primitive(type_SelectETEB),
et_id(p_et->get_id()),
eb_index(p_eb_index),
deleg(p_delegate)
{
   Q_ASSERT(deleg);
   prepare_base(p_doc);
}
SelectETEB::~SelectETEB()
{
   delete deleg;
}
Primitive *SelectETEB::create(unsigned int type, RestoreStream &p_stream)
{
   PrimitiveDelegate *prim = PrimitiveDelegate::create(p_stream);
   switch(prim->get_type())
   {
   case type_ETSetEBName:
   case type_ETSetEBAmount:
   case type_ETSetEBScale:
   case type_ETSetEBSynchronized:
   case type_ETSetEBPosition:
   case type_ETSetEBAngle:
   case type_ETSetEBAngularVelocity:
   case type_ETSetEBParticle:
   case type_ETSetEBEmitter:
      break;
   default:
      delete prim;
      throw RestoreError(qApp->translate("Primitive","wrong type of PrimitiveDelegate while reading Primitives::SelectETEB"));
   }
   return new SelectETEB(static_cast<ETEBPrimitiveDelegate*>(prim));
}
UiError SelectETEB::exec_impl(Document *doc)
{
   EmitterTemplate *et=qobject_cast<EmitterTemplate*>(doc->lookup_object(et_id));
   if (!et)
      return qApp->translate("Primitive","Emitter template not found or type mismatch.");
   if (eb_index < 0 || eb_index >= et->emitter_blocks.size())
      return qApp->translate("Primitive","Emitter block index %1 out of range in '%2'.").arg(eb_index).arg(et->get_name());
   EmitterTemplate::EmitterBlock &eb = et->emitter_blocks[eb_index];
   UiError err = deleg->exec_impl(doc, et, eb, this);
   return err;
}
UiError SelectETEB::undo_impl(Document *doc)
{
   EmitterTemplate *et=qobject_cast<EmitterTemplate*>(doc->lookup_object(et_id));
   if (!et)
      return qApp->translate("Primitive","Emitter template not found or type mismatch.");
   if (eb_index < 0 || eb_index >= et->emitter_blocks.size())
      return qApp->translate("Primitive","Emitter block index %1 out of range in '%2'.").arg(eb_index).arg(et->get_name());
   EmitterTemplate::EmitterBlock &eb = et->emitter_blocks[eb_index];
   UiError err = deleg->undo_impl(doc, et, eb, this);
   return err;
}
void SelectETEB::store_data_impl(QDataStream& p_stream) const
{
   deleg->store_data(p_stream);
   p_stream << et_id << eb_index;
}
void SelectETEB::restore_data_impl(RestoreStream& p_stream)
{
   deleg->restore_data(p_stream);
   p_stream >> et_id >> eb_index;
}
//
ETSetEBName::ETSetEBName(QString p_name)
:
ETEBPrimitiveDelegate(type_ETSetEBName), eb_name(p_name)
{
}
PrimitiveDelegate *ETSetEBName::create(unsigned int type, RestoreStream &p_stream)
{
   return new ETSetEBName;
}
ETSetEBName::ETSetEBName()
:
ETEBPrimitiveDelegate(type_ETSetEBName)
{
}
UiError ETSetEBName::exec_impl(Document *doc, model::EmitterTemplate *p_et, model::EmitterTemplate::EmitterBlock &p_eb, Primitive *p_parent)
{
   std::swap(p_eb.name, eb_name);
   return UiError();
}
UiError ETSetEBName::undo_impl(Document *doc, model::EmitterTemplate *p_et, model::EmitterTemplate::EmitterBlock &p_eb, Primitive *p_parent)
{
   return exec_impl(doc, p_et, p_eb, p_parent);
}
void ETSetEBName::store_data_impl(QDataStream& p_stream) const
{
   p_stream << eb_name;
}
void ETSetEBName::restore_data_impl(RestoreStream& p_stream)
{
   p_stream >> eb_name;
}
//
ETSetEBAmount::ETSetEBAmount(unsigned int p_amount)
:
ETEBPrimitiveDelegate(type_ETSetEBAmount), amount(p_amount)
{
}
PrimitiveDelegate *ETSetEBAmount::create(unsigned int type, RestoreStream &p_stream)
{
   return new ETSetEBAmount;
}
ETSetEBAmount::ETSetEBAmount()
:
ETEBPrimitiveDelegate(type_ETSetEBAmount)
{
}
UiError ETSetEBAmount::exec_impl(Document *doc, model::EmitterTemplate *p_et, model::EmitterTemplate::EmitterBlock &p_eb, Primitive *p_parent)
{
   std::swap(p_eb.amount, amount);
   return UiError();
}
UiError ETSetEBAmount::undo_impl(Document *doc, model::EmitterTemplate *p_et, model::EmitterTemplate::EmitterBlock &p_eb, Primitive *p_parent)
{
   return exec_impl(doc, p_et, p_eb, p_parent);
}
void ETSetEBAmount::store_data_impl(QDataStream& p_stream) const
{
   p_stream << amount;
}
void ETSetEBAmount::restore_data_impl(RestoreStream& p_stream)
{
   p_stream >> amount;
}
//
ETSetEBScale::ETSetEBScale(const RandomDouble &p_scale)
:
ETEBPrimitiveDelegate(type_ETSetEBScale), scale(p_scale)
{
}
PrimitiveDelegate *ETSetEBScale::create(unsigned int type, RestoreStream &p_stream)
{
   return new ETSetEBScale;
}
ETSetEBScale::ETSetEBScale()
:
ETEBPrimitiveDelegate(type_ETSetEBScale)
{
}
UiError ETSetEBScale::exec_impl(Document *doc, model::EmitterTemplate *p_et, model::EmitterTemplate::EmitterBlock &p_eb, Primitive *p_parent)
{
   std::swap(p_eb.scale, scale);
   return UiError();
}
UiError ETSetEBScale::undo_impl(Document *doc, model::EmitterTemplate *p_et, model::EmitterTemplate::EmitterBlock &p_eb, Primitive *p_parent)
{
   return exec_impl(doc, p_et, p_eb, p_parent);
}
void ETSetEBScale::store_data_impl(QDataStream& p_stream) const
{
   p_stream << scale;
}
void ETSetEBScale::restore_data_impl(RestoreStream& p_stream)
{
   p_stream >> scale;
}
//
ETSetEBSynchronized::ETSetEBSynchronized(bool p_synchronized)
:
ETEBPrimitiveDelegate(type_ETSetEBSynchronized), synchronized(p_synchronized)
{
}
PrimitiveDelegate *ETSetEBSynchronized::create(unsigned int type, RestoreStream &p_stream)
{
   return new ETSetEBSynchronized;
}
ETSetEBSynchronized::ETSetEBSynchronized()
:
ETEBPrimitiveDelegate(type_ETSetEBSynchronized)
{
}
UiError ETSetEBSynchronized::exec_impl(Document *doc, model::EmitterTemplate *p_et, model::EmitterTemplate::EmitterBlock &p_eb, Primitive *p_parent)
{
   std::swap(p_eb.synchronized, synchronized);
   return UiError();
}
UiError ETSetEBSynchronized::undo_impl(Document *doc, model::EmitterTemplate *p_et, model::EmitterTemplate::EmitterBlock &p_eb, Primitive *p_parent)
{
   return exec_impl(doc, p_et, p_eb, p_parent);
}
void ETSetEBSynchronized::store_data_impl(QDataStream& p_stream) const
{
   p_stream << synchronized;
}
void ETSetEBSynchronized::restore_data_impl(RestoreStream& p_stream)
{
   p_stream >> synchronized;
}
//
ETSetEBPosition::ETSetEBPosition(const RandomPosition &p_position)
:
ETEBPrimitiveDelegate(type_ETSetEBPosition), position(p_position)
{
}
PrimitiveDelegate *ETSetEBPosition::create(unsigned int type, RestoreStream &p_stream)
{
   return new ETSetEBPosition;
}
ETSetEBPosition::ETSetEBPosition()
:
ETEBPrimitiveDelegate(type_ETSetEBPosition)
{
}
UiError ETSetEBPosition::exec_impl(Document *doc, model::EmitterTemplate *p_et, model::EmitterTemplate::EmitterBlock &p_eb, Primitive *p_parent)
{
   std::swap(p_eb.position, position);
   return UiError();
}
UiError ETSetEBPosition::undo_impl(Document *doc, model::EmitterTemplate *p_et, model::EmitterTemplate::EmitterBlock &p_eb, Primitive *p_parent)
{
   return exec_impl(doc, p_et, p_eb, p_parent);
}
void ETSetEBPosition::store_data_impl(QDataStream& p_stream) const
{
   p_stream << position;
}
void ETSetEBPosition::restore_data_impl(RestoreStream& p_stream)
{
   p_stream >> position;
}
//
ETSetEBAngle::ETSetEBAngle(const RandomPosition &p_angle)
:
ETEBPrimitiveDelegate(type_ETSetEBAngle), angle(p_angle)
{
}
PrimitiveDelegate *ETSetEBAngle::create(unsigned int type, RestoreStream &p_stream)
{
   return new ETSetEBAngle;
}
ETSetEBAngle::ETSetEBAngle()
:
ETEBPrimitiveDelegate(type_ETSetEBAngle)
{
}
UiError ETSetEBAngle::exec_impl(Document *doc, model::EmitterTemplate *p_et, model::EmitterTemplate::EmitterBlock &p_eb, Primitive *p_parent)
{
   std::swap(p_eb.angle, angle);
   return UiError();
}
UiError ETSetEBAngle::undo_impl(Document *doc, model::EmitterTemplate *p_et, model::EmitterTemplate::EmitterBlock &p_eb, Primitive *p_parent)
{
   return exec_impl(doc, p_et, p_eb, p_parent);
}
void ETSetEBAngle::store_data_impl(QDataStream& p_stream) const
{
   p_stream << angle;
}
void ETSetEBAngle::restore_data_impl(RestoreStream& p_stream)
{
   p_stream >> angle;
}
//
ETSetEBAngularVelocity::ETSetEBAngularVelocity(const RandomPosition &p_angular_velocity)
:
ETEBPrimitiveDelegate(type_ETSetEBAngularVelocity), angular_velocity(p_angular_velocity)
{
}
PrimitiveDelegate *ETSetEBAngularVelocity::create(unsigned int type, RestoreStream &p_stream)
{
   return new ETSetEBAngularVelocity;
}
ETSetEBAngularVelocity::ETSetEBAngularVelocity()
:
ETEBPrimitiveDelegate(type_ETSetEBAngularVelocity)
{
}
UiError ETSetEBAngularVelocity::exec_impl(Document *doc, model::EmitterTemplate *p_et, model::EmitterTemplate::EmitterBlock &p_eb, Primitive *p_parent)
{
   std::swap(p_eb.angular_velocity, angular_velocity);
   return UiError();
}
UiError ETSetEBAngularVelocity::undo_impl(Document *doc, model::EmitterTemplate *p_et, model::EmitterTemplate::EmitterBlock &p_eb, Primitive *p_parent)
{
   return exec_impl(doc, p_et, p_eb, p_parent);
}
void ETSetEBAngularVelocity::store_data_impl(QDataStream& p_stream) const
{
   p_stream << angular_velocity;
}
void ETSetEBAngularVelocity::restore_data_impl(RestoreStream& p_stream)
{
   p_stream >> angular_velocity;
}
//
ETSetEBParticle::ETSetEBParticle(ParticleTemplate *p_particle)
:
ETEBPrimitiveDelegate(type_ETSetEBParticle), particle_id(p_particle ? p_particle->get_id() : Id())
{
}
PrimitiveDelegate *ETSetEBParticle::create(unsigned int type, RestoreStream &p_stream)
{
   return new ETSetEBParticle;
}
ETSetEBParticle::ETSetEBParticle()
:
ETEBPrimitiveDelegate(type_ETSetEBParticle)
{
}
UiError ETSetEBParticle::exec_impl(Document *doc, model::EmitterTemplate *p_et, model::EmitterTemplate::EmitterBlock &p_eb, Primitive *p_parent)
{
   ParticleTemplate *particle;
   if (particle_id.is_invalid()) {
      particle = 0;
   } else {
      particle = qobject_cast<ParticleTemplate*>(doc->lookup_object(particle_id));
      if (!particle) {
         return qApp->translate("Primitive","Particle template not found or wrong type.");
      }
   }
   particle_id = p_eb.particle ? p_eb.particle->get_id() : Id();
   p_eb.particle = particle;
   return UiError();
}
UiError ETSetEBParticle::undo_impl(Document *doc, model::EmitterTemplate *p_et, model::EmitterTemplate::EmitterBlock &p_eb, Primitive *p_parent)
{
   return exec_impl(doc, p_et, p_eb, p_parent);
}
void ETSetEBParticle::store_data_impl(QDataStream& p_stream) const
{
   p_stream << particle_id;
}
void ETSetEBParticle::restore_data_impl(RestoreStream& p_stream)
{
   p_stream >> particle_id;
}
//
ETSetEBEmitter::ETSetEBEmitter(EmitterTemplate *p_emitter)
:
ETEBPrimitiveDelegate(type_ETSetEBEmitter), emitter_id(p_emitter ? p_emitter->get_id() : Id())
{
}
PrimitiveDelegate *ETSetEBEmitter::create(unsigned int type, RestoreStream &p_stream)
{
   return new ETSetEBEmitter;
}
ETSetEBEmitter::ETSetEBEmitter()
:
ETEBPrimitiveDelegate(type_ETSetEBEmitter)
{
}
UiError ETSetEBEmitter::exec_impl(Document *doc, model::EmitterTemplate *p_et, model::EmitterTemplate::EmitterBlock &p_eb, Primitive *p_parent)
{
   EmitterTemplate *emitter;
   if (emitter_id.is_invalid()) {
      emitter = 0;
   } else {
      emitter = qobject_cast<EmitterTemplate*>(doc->lookup_object(emitter_id));
      if (!emitter) {
         return qApp->translate("Primitive","Emitter template not found or wrong type.");
      }
      if (emitter == p_et)
         return qApp->translate("Primitive","Emitter template can not reference itself.");
   }
   emitter_id = p_eb.emitter ? p_eb.emitter->get_id() : Id();
   p_eb.emitter = emitter;
   return UiError();
}
UiError ETSetEBEmitter::undo_impl(Document *doc, model::EmitterTemplate *p_et, model::EmitterTemplate::EmitterBlock &p_eb, Primitive *p_parent)
{
   return exec_impl(doc, p_et, p_eb, p_parent);
}
void ETSetEBEmitter::store_data_impl(QDataStream& p_stream) const
{
   p_stream << emitter_id;
}
void ETSetEBEmitter::restore_data_impl(RestoreStream& p_stream)
{
   p_stream >> emitter_id;
}
//
static class CreatorInstaller {
public:
   CreatorInstaller();
} creator_installer;
CreatorInstaller::CreatorInstaller() {
   Primitive::install_creator_function(type_InsertContainment,InsertContainment::create);
   Primitive::install_creator_function(type_RemoveContainment,RemoveContainment::create);
   Primitive::install_creator_function(type_MoveChild,MoveChild::create);
   Primitive::install_creator_function(type_NewDataObject,NewDataObject::create);
   Primitive::install_creator_function(type_DelDataObject,DelDataObject::create);
   Primitive::install_creator_function(type_SetDataObjectName,SetDataObjectName::create);
   Primitive::install_creator_function(type_RemoveParticleTemplate,RemoveParticleTemplate::create);
   Primitive::install_creator_function(type_RemoveEmitterTemplate,RemoveEmitterTemplate::create);
   Primitive::install_creator_function(type_SelectPT,SelectPT::create);
   PrimitiveDelegate::install_creator_function(type_SetPTVisible,SetPTVisible::create);
   PrimitiveDelegate::install_creator_function(type_SetPTLifeTime,SetPTLifeTime::create);
   PrimitiveDelegate::install_creator_function(type_SetPTDensity,SetPTDensity::create);
   PrimitiveDelegate::install_creator_function(type_SetPTGravitationEnabled,SetPTGravitationEnabled::create);
   PrimitiveDelegate::install_creator_function(type_SetPTFrictionEnabled,SetPTFrictionEnabled::create);
   PrimitiveDelegate::install_creator_function(type_SetPTShape,SetPTShape::create);
   PrimitiveDelegate::install_creator_function(type_SetPTTextureFile,SetPTTextureFile::create);
   PrimitiveDelegate::install_creator_function(type_SetPTTileS,SetPTTileS::create);
   PrimitiveDelegate::install_creator_function(type_SetPTTileT,SetPTTileT::create);
   PrimitiveDelegate::install_creator_function(type_SetPTNumTiles,SetPTNumTiles::create);
   PrimitiveDelegate::install_creator_function(type_SetPTTileSpeedMode,SetPTTileSpeedMode::create);
   PrimitiveDelegate::install_creator_function(type_PTNewTimeMark,PTNewTimeMark::create);
   PrimitiveDelegate::install_creator_function(type_PTRemTimeMark,PTRemTimeMark::create);
   PrimitiveDelegate::install_creator_function(type_PTRenameTimeMark,PTRenameTimeMark::create);
   PrimitiveDelegate::install_creator_function(type_PTChangeTimeMark,PTChangeTimeMark::create);
   PrimitiveDelegate::install_creator_function(type_PTNewEB,PTNewEB::create);
   PrimitiveDelegate::install_creator_function(type_PTRemEB,PTRemEB::create);
   Primitive::install_creator_function(type_SelectPTEB,SelectPTEB::create);
   PrimitiveDelegate::install_creator_function(type_PTSetEBName,PTSetEBName::create);
   PrimitiveDelegate::install_creator_function(type_PTSetEBEmitter,PTSetEBEmitter::create);
   PrimitiveDelegate::install_creator_function(type_PTSetEBTime1,PTSetEBTime1::create);
   PrimitiveDelegate::install_creator_function(type_PTSetEBTime2,PTSetEBTime2::create);
   PrimitiveDelegate::install_creator_function(type_PTSetEBIntervalMin,PTSetEBIntervalMin::create);
   PrimitiveDelegate::install_creator_function(type_PTSetEBIntervalMax,PTSetEBIntervalMax::create);
   PrimitiveDelegate::install_creator_function(type_PTColorCPSetConst,PTColorCPSetConst::create);
   PrimitiveDelegate::install_creator_function(type_PTColorCPSetLine,PTColorCPSetLine::create);
   PrimitiveDelegate::install_creator_function(type_PTNewColorCP,PTNewColorCP::create);
   PrimitiveDelegate::install_creator_function(type_PTRemColorCP,PTRemColorCP::create);
   PrimitiveDelegate::install_creator_function(type_PTSetColorCPValue,PTSetColorCPValue::create);
   PrimitiveDelegate::install_creator_function(type_PTAlphaCPSetConst,PTAlphaCPSetConst::create);
   PrimitiveDelegate::install_creator_function(type_PTAlphaCPSetLine,PTAlphaCPSetLine::create);
   PrimitiveDelegate::install_creator_function(type_PTNewAlphaCP,PTNewAlphaCP::create);
   PrimitiveDelegate::install_creator_function(type_PTRemAlphaCP,PTRemAlphaCP::create);
   PrimitiveDelegate::install_creator_function(type_PTSetAlphaCPValue,PTSetAlphaCPValue::create);
   PrimitiveDelegate::install_creator_function(type_PTSizeCPSetConst,PTSizeCPSetConst::create);
   PrimitiveDelegate::install_creator_function(type_PTSizeCPSetLine,PTSizeCPSetLine::create);
   PrimitiveDelegate::install_creator_function(type_PTNewSizeCP,PTNewSizeCP::create);
   PrimitiveDelegate::install_creator_function(type_PTRemSizeCP,PTRemSizeCP::create);
   PrimitiveDelegate::install_creator_function(type_PTSetSizeCPValue,PTSetSizeCPValue::create);
   PrimitiveDelegate::install_creator_function(type_PTRadiusCPSetConst,PTRadiusCPSetConst::create);
   PrimitiveDelegate::install_creator_function(type_PTRadiusCPSetLine,PTRadiusCPSetLine::create);
   PrimitiveDelegate::install_creator_function(type_PTNewRadiusCP,PTNewRadiusCP::create);
   PrimitiveDelegate::install_creator_function(type_PTRemRadiusCP,PTRemRadiusCP::create);
   PrimitiveDelegate::install_creator_function(type_PTSetRadiusCPValue,PTSetRadiusCPValue::create);
   Primitive::install_creator_function(type_SelectETEB,SelectETEB::create);
   PrimitiveDelegate::install_creator_function(type_ETSetEBName,ETSetEBName::create);
   PrimitiveDelegate::install_creator_function(type_ETSetEBAmount,ETSetEBAmount::create);
   PrimitiveDelegate::install_creator_function(type_ETSetEBScale,ETSetEBScale::create);
   PrimitiveDelegate::install_creator_function(type_ETSetEBSynchronized,ETSetEBSynchronized::create);
   PrimitiveDelegate::install_creator_function(type_ETSetEBPosition,ETSetEBPosition::create);
   PrimitiveDelegate::install_creator_function(type_ETSetEBAngle,ETSetEBAngle::create);
   PrimitiveDelegate::install_creator_function(type_ETSetEBAngularVelocity,ETSetEBAngularVelocity::create);
   PrimitiveDelegate::install_creator_function(type_ETSetEBParticle,ETSetEBParticle::create);
   PrimitiveDelegate::install_creator_function(type_ETSetEBEmitter,ETSetEBEmitter::create);
}
